postgresql Postgres使用COALESCE函数忽略索引

qv7cva1a  于 2022-11-23  发布在  PostgreSQL
关注(0)|答案(1)|浏览(161)

我有下面的表,大约有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';
omjgkv6w

omjgkv6w1#

我找到了解决办法,为了强制DB使用我的索引,我添加了一个“ORDER BY”子句,而且它似乎起作用了:
第一个

相关问题