在Postgres中,添加LIMIT
时,某些查询要慢得多:
SELECT * FROM review WHERE clicker_id=28 ORDER BY done DESC LIMIT 4; -- 51 sec
SELECT * FROM review WHERE clicker_id=28 ORDER BY id, done DESC LIMIT 4; -- 0.020s
SELECT * FROM review WHERE clicker_id=28 LIMIT 4; -- 0.007s
SELECT * FROM review WHERE clicker_id=28 ORDER BY id; -- 0.007s
您可以看到,我需要在ORDER BY
上添加一个虚拟ID,以便快速运行。我试图了解原因。
在它们上运行EXPLAIN
:
EXPLAIN SELECT * FROM review WHERE clicker_id=28 ORDER BY done DESC LIMIT 4;
EXPLAIN SELECT * FROM review WHERE clicker_id=28 ORDER BY id, done DESC LIMIT 4;
EXPLAIN SELECT * FROM review WHERE clicker_id=28 LIMIT 4;
EXPLAIN SELECT * FROM review WHERE clicker_id=28 ORDER BY id;
给出答案:
EXPLAIN SELECT * FROM review WHERE clicker_id=28 ORDER BY done DESC LIMIT 4
Limit (cost=0.44..249.76 rows=4 width=56)
-> Index Scan using review_done on review (cost=0.44..913081.13 rows=14649 width=56)
Filter: (clicker_id = 28)
EXPLAIN SELECT * FROM review WHERE clicker_id=28 ORDER BY id, done DESC LIMIT 4
Limit (cost=11970.75..11970.76 rows=4 width=56)
-> Sort (cost=11970.75..12007.37 rows=14649 width=56)
Sort Key: id, done DESC
-> Index Scan using review_clicker_id on review (cost=0.44..11751.01 rows=14649 width=56)
Index Cond: (clicker_id = 28)
EXPLAIN SELECT * FROM review WHERE clicker_id=28 LIMIT 4
Limit (cost=0.44..3.65 rows=4 width=56)
-> Index Scan using review_clicker_id on review (cost=0.44..11751.01 rows=14649 width=56)
Index Cond: (clicker_id = 28)
EXPLAIN SELECT * FROM review WHERE clicker_id=28 ORDER BY id
Sort (cost=12764.61..12801.24 rows=14649 width=56)
Sort Key: id
-> Index Scan using review_clicker_id on review (cost=0.44..11751.01 rows=14649 width=56)
Index Cond: (clicker_id = 28)
我不是SQL专家,但我认为Postgres期望查询比实际速度快,因此使用一种方法来获取实际上不合适的数据,对吗?
review
表:LIMIT 288
,那么它会快得多(<1秒),但是如果我对有7066行的用户执行相同的操作,那它会变得非常慢。ORDER BY
之前,我尝试了这些:analyze review;
没有帮助。
我的问题本身已经解决,但是我对此不满意:
ORDER BY
以加快速度?将来EXPLAIN
没那么有用:谢谢!
类似问题:
在Postgres中,添加LIMIT时,某些查询要慢得多:查询:SELECT * FROM review WHERE clicker_id = 28 ORDER BY done DESC LIMIT 4; -51秒SELECT * FROM review WHERE ...
这里的根本问题是所谓的提前中止查询计划。这是一个来自pgsql-hackers的线程,描述了类似的内容: