在postgres中使用LIMIT时未使用的索引

时间:2011-12-19 20:11:29

标签: sql postgresql indexing

我有一个带有索引的单词表(language_id,state)。以下是EXPLAIN ANALYZE的结果:

无限制

explain analyze SELECT "words".* FROM "words" WHERE (words.language_id = 27) AND (state IS NULL);

Bitmap Heap Scan on words  (cost=10800.38..134324.10 rows=441257 width=96) (actual time=233.257..416.026 rows=540556 loops=1)
Recheck Cond: ((language_id = 27) AND (state IS NULL))
->  Bitmap Index Scan on ls  (cost=0.00..10690.07 rows=441257 width=0) (actual time=230.849..230.849 rows=540556 loops=1)
Index Cond: ((language_id = 27) AND (state IS NULL))
Total runtime: 460.277 ms
(5 rows)

限制100

explain analyze SELECT "words".* FROM "words" WHERE (words.language_id = 27) AND (state IS NULL) LIMIT 100;

Limit  (cost=0.00..51.66 rows=100 width=96) (actual time=0.081..0.184 rows=100 loops=1)
->  Seq Scan on words  (cost=0.00..227935.59 rows=441257 width=96) (actual time=0.080..0.160 rows=100 loops=1)
Filter: ((state IS NULL) AND (language_id = 27))
Total runtime: 0.240 ms
(4 rows)

为什么会这样?如何在所有情况下都使用索引?

感谢。

4 个答案:

答案 0 :(得分:7)

我认为PostgreSQL查询规划器只是认为在第二种情况下 - 具有LIMIT的情况 - 因为它[LIMIT]太小而不值得应用索引。所以这不是问题。

答案 1 :(得分:5)

查看有关Using EXPLAINQuery Planning的PostgreSQL文档。查询计划程序更喜欢在LIMIT 100情况下对索引扫描进行顺序扫描的原因仅仅是因为顺序扫描更便宜。

查询中没有ORDER BY子句,因此规划器可以使用与过滤条件匹配的前100个(随机)行。索引扫描需要首先读取索引页,然后读取数据页以获取相应的行。顺序扫描只需读取数据页面即可获取行。在您的情况下,表统计信息似乎表明有足够的(随机)行匹配过滤条件。获取100行的顺序页面读取的成本被认为比首先读取索引的成本便宜,然后获取实际的行。当您提高限制或较少的行与过滤条件匹配时,您可能会看到不同的计划。

使用默认设置,计划程序会将随机页面读取的成本( random_page_cost )视为连续页面读取成本的四倍( seq_page_cost )。可以调整这些设置以调整查询计划(例如,当整个数据库在RAM中时,随机页面读取并不比顺序页面读取更昂贵并且应该优选索引扫描)。您还可以通过启用/禁用某些类型的扫描来尝试不同的查询计划,例如:

set enable_seqscan = [on | off]
set enable_indexscan = [on | off]

虽然可以在全局范围内启用/禁用某些类型的扫描,但这应该仅用于每个会话的调试或故障排除。

在测试查询计划之前运行VACUUM ANALYZE words,否则测试之间运行的自动真空( autovaccum )可能会影响结果。

答案 2 :(得分:3)

无限制:rows = 540556 loops = 1总运行时间:460.277 ms

使用limit:rows = 100 loops = 1 Total runtime:0.240 ms

我在这里看不到问题。如果您的查询产生500K行,则需要更多时间。

答案 3 :(得分:0)

两个查询返回不同数量的行也很奇怪。我猜你一直在插入...嗯,如果你做一个子选择怎么办?

select * from (select ...) limit 100;