Postgres 索引对原始 SQL 与 ActiveRecord 查询的影响截然不同

Postgres index has massively different impact on raw SQL vs ActiveRecord query

我有一个包含 150k 个名字的 table,并尝试向 lower(name) 添加索引以加快查找速度。索引将原始 SQL 查询速度提高了大约 x100,但使用 ActiveRecord 执行的相同查询不受影响,如果不是慢一点的话。

这些是查询:

NamedEntity.where("lower(name) = ?", "John Doe".downcase).first

对比

conn.execute(
  %q{SELECT "named_entities".* FROM "named_entities" WHERE (lower(name) = 'john doe');}
)

我用

添加了索引
CREATE INDEX index_named_entities_on_lower_name ON named_entities USING btree (lower(name));

以下是比较所有案例的基准(每个案例执行 50 次):

no index,   AR:  6.999421
with index, AR:  7.264234
no index,   SQL: 5.569600
with index, SQL: 0.045464

AR 和 SQL 的查询计划完全相同。

没有索引:

Seq Scan on named_entities  (cost=0.00..2854.31 rows=785 width=130)
  Filter: (lower((name)::text) = 'john doe'::text)

并带有索引:

Bitmap Heap Scan on named_entities  (cost=9.30..982.51 rows=785 width=130)
  Recheck Cond: (lower((name)::text) = 'john doe'::text)
  ->  Bitmap Index Scan on index_named_entities_on_lower_name  (cost=0.00..9.26 rows=785 width=0)
        Index Cond: (lower((name)::text) = 'john doe'::text)

我不知道该如何解释。 ActiveRecord 增加的开销应该不受索引的影响,所以索引和无索引之间的 速度差异 对于 AR 和 SQL 应该是相同的,不是吗?

我找到了解决问题的方法,方法是在创建索引后添加 ANALYZE named_entities;。这使得 Postgres 更新其关于各种事物的统计信息,因此它可以生成更好的查询计划。 (还发现Postgres docs很厉害。)

这仍然不能解释时间差异,因为 explains 表明 SQL 和 AR 查询导致相同的慢查询计划。