我有下面的表,大约有400万行:
CREATE TABLE members (
id INTEGER PRIMARY KEY GENERATED ALWAYS AS IDENTITY,
created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP NOT NULL,
updated_at TIMESTAMP WITH TIME ZONE,
-- other columns...
);
我使用以下查询来提取最新更新的行:
SELECT *
FROM members
WHERE COALESCE(updated_at, created_at) > current_timestamp - interval '24 hours'
这个查询显然很慢,所以我创建了一个索引,但是Postgres没有使用它:
CREATE INDEX members_updated_or_created_at ON members(COALESCE(updated_at, created_at));
执行计划如下:
Seq Scan on members (cost=0.00..171792.01 rows=1326991 width=1826) (actual time=62.663..22064.805 rows=1 loops=1)
Filter: (COALESCE(updated_at, created_at) > (CURRENT_TIMESTAMP - '48:00:00'::interval))
Rows Removed by Filter: 3980971
Planning Time: 0.123 ms
JIT:
Functions: 2
Options: Inlining false, Optimization false, Expressions true, Deforming true
Timing: Generation 7.481 ms, Inlining 0.000 ms, Optimization 8.067 ms, Emission 35.308 ms, Total 50.857 ms
Execution Time: 22072.906 ms
我不明白为什么它要进行表扫描而不是使用索引扫描。我也试着选择更少的字段,并添加一个限制,但它没有改变任何东西。
编辑:
因此,看起来好像没有使用索引,因为我正在获取索引中不存在的许多列(选择 *)。
我尝试对updated_at
列执行相同的操作,这次,如果我选择的唯一列是“updated_at”列(仅扫描索引),则使用索引,但如果我包括另一列,则不使用索引。
我不明白的是,为什么我没有得到相同的行为与合并功能?
此查询将导致全表扫描
SELECT coalesce(updated_at, created_at)
FROM members
WHERE coalesce(updated_at, created_at) > current_timestamp - interval '7 days';
此查询将导致“仅索引扫描”(updated_at上的索引)
SELECT updated_at
FROM members
WHERE updated_at > current_timestamp - interval '7 days';
1条答案
按热度按时间omjgkv6w1#
我找到了解决办法,为了强制DB使用我的索引,我添加了一个“ORDER BY”子句,而且它似乎起作用了:
第一个