jak*_*xer 33 sql postgresql sql-order-by query-optimization limit
我有一张桌子,我们称之为"foos",其中有近600万条记录.我正在运行以下查询:
SELECT "foos".*
FROM "foos"
INNER JOIN "bars" ON "foos".bar_id = "bars".id
WHERE (("bars".baz_id = 13266))
ORDER BY "foos"."id" DESC
LIMIT 5 OFFSET 0;
Run Code Online (Sandbox Code Playgroud)
此查询需要很长时间才能运行(Rails在运行时会超时).所有ID都有一个索引.好奇的部分是,如果我删除ORDER BY条款或LIMIT条款,它几乎是瞬间运行.
我假定这两者的存在ORDER BY和LIMIT正在做的PostgreSQL查询规划一些错误的选择.任何人都有任何想法如何解决这个问题?
如果它有帮助,这里是EXPLAIN所有3种情况:
//////// Both ORDER and LIMIT
SELECT "foos".*
FROM "foos"
INNER JOIN "bars" ON "foos".bar_id = "bars".id
WHERE (("bars".baz_id = 13266))
ORDER BY "foos"."id" DESC
LIMIT 5 OFFSET 0;
QUERY PLAN
--------------------------------------------------------------------------------------------------------------------
Limit (cost=0.00..16663.44 rows=5 width=663)
-> Nested Loop (cost=0.00..25355084.05 rows=7608 width=663)
Join Filter: (foos.bar_id = bars.id)
-> Index Scan Backward using foos_pkey on foos (cost=0.00..11804133.33 rows=4963477 width=663)
Filter: (((NOT privacy_protected) OR (user_id = 67962)) AND ((status)::text = 'DONE'::text))
-> Materialize (cost=0.00..658.96 rows=182 width=4)
-> Index Scan using index_bars_on_baz_id on bars (cost=0.00..658.05 rows=182 width=4)
Index Cond: (baz_id = 13266)
(8 rows)
//////// Just LIMIT
SELECT "foos".*
FROM "foos"
INNER JOIN "bars" ON "foos".bar_id = "bars".id
WHERE (("bars".baz_id = 13266))
LIMIT 5 OFFSET 0;
QUERY PLAN
---------------------------------------------------------------------------------------------------------------------------------------
Limit (cost=0.00..22.21 rows=5 width=663)
-> Nested Loop (cost=0.00..33788.21 rows=7608 width=663)
-> Index Scan using index_bars_on_baz_id on bars (cost=0.00..658.05 rows=182 width=4)
Index Cond: (baz_id = 13266)
-> Index Scan using index_foos_on_bar_id on foos (cost=0.00..181.51 rows=42 width=663)
Index Cond: (foos.bar_id = bars.id)
Filter: (((NOT foos.privacy_protected) OR (foos.user_id = 67962)) AND ((foos.status)::text = 'DONE'::text))
(7 rows)
//////// Just ORDER
SELECT "foos".*
FROM "foos"
INNER JOIN "bars" ON "foos".bar_id = "bars".id
WHERE (("bars".baz_id = 13266))
ORDER BY "foos"."id" DESC;
QUERY PLAN
---------------------------------------------------------------------------------------------------------------------------------------
Sort (cost=36515.17..36534.19 rows=7608 width=663)
Sort Key: foos.id
-> Nested Loop (cost=0.00..33788.21 rows=7608 width=663)
-> Index Scan using index_bars_on_baz_id on bars (cost=0.00..658.05 rows=182 width=4)
Index Cond: (baz_id = 13266)
-> Index Scan using index_foos_on_bar_id on foos (cost=0.00..181.51 rows=42 width=663)
Index Cond: (foos.bar_id = bars.id)
Filter: (((NOT foos.privacy_protected) OR (foos.user_id = 67962)) AND ((foos.status)::text = 'DONE'::text))
(8 rows)
Run Code Online (Sandbox Code Playgroud)
And*_*rus 15
当你同时拥有LIMIT和ORDER BY时,优化器已经决定通过按键降序跛行foo上的未过滤记录会更快,直到它获得其余条件的五个匹配.在其他情况下,它只是将查询作为嵌套循环运行并返回所有记录.
另一方面,我要说的问题是PG并没有理解各种ID 的联合分布,这就是为什么该计划如此次优.
对于可能的解决方案:我假设您最近运行过ANALYZE.如果没有,请这样做.这可以解释为什么即使对于快速返回的版本,您的估计时间也很高.如果问题仍然存在,可以将ORDER BY作为子选择运行,并在外部查询中打开LIMIT.
可能会发生这种情况,因为在它尝试订购然后选择之前。为什么不尝试在外部全选中对结果进行排序?类似于: SELECT * FROM (SELECT ... INNER JOIN ETC...) ORDER BY ... DESC
| 归档时间: |
|
| 查看次数: |
21210 次 |
| 最近记录: |