【发布时间】:2013-09-04 05:54:41
【问题描述】:
PostgreSQL 查询的LEFT JOIN 部分运行非常缓慢,我不知道为什么。
完整的查询:
SELECT t.id FROM tests t
LEFT JOIN tests c ON c.parent_id IN (t.id, t.parent_id)
INNER JOIN responses r ON (
r.test_id IN (t.id, t.parent_id, c.id)
) WHERE r.user_id = 333
tests.id 和 tests.parent_id 上有索引。
测试包含 28876 行(其中有 1282 行 WHERE parent_id IS NOT NULL)。
查询的 LEFT JOIN 部分生成 32098 行,大约需要 700 毫秒。
SELECT t.id FROM tests t
LEFT JOIN tests c ON c.parent_id IN (t.id, t.parent_id)
查询的其余部分花费的时间可以忽略不计。
关于为什么它可能很慢的任何想法,或者实现相同目标的更好方法?
谢谢!
选择版本()
PostgreSQL 9.1.9 on x86_64-unknown-linux-gnu, compiled by gcc (Ubuntu/Linaro 4.6.3-1ubuntu5) 4.6.3, 64-bit
解释分析
(注意:这里使用的是真实的表名usability_tests,我在前面的示例中将其简化为tests。)
Nested Loop (cost=5.18..158692.45 rows=80 width=4) (actual time=107.873..5718.295 rows=103 loops=1)
Join Filter: ((r.usability_test_id = t.id) OR (r.usability_test_id = t.parent_id) OR (r.usability_test_id = c.id))
-> Nested Loop Left Join (cost=0.56..136015.63 rows=28876 width=12) (actual time=0.091..486.496 rows=32098 loops=1)
Join Filter: ((c.parent_id = t.id) OR (c.parent_id = t.parent_id))
-> Seq Scan on usability_tests t (cost=0.00..1455.76 rows=28876 width=8) (actual time=0.042..39.558 rows=28876 loops=1)
-> Bitmap Heap Scan on usability_tests c (cost=0.56..4.60 rows=4 width=8) (actual time=0.010..0.011 rows=0 loops=28876)
Recheck Cond: ((parent_id = t.id) OR (parent_id = t.parent_id))
-> BitmapOr (cost=0.56..0.56 rows=4 width=0) (actual time=0.008..0.008 rows=0 loops=28876)
-> Bitmap Index Scan on index_usability_tests_on_parent_id (cost=0.00..0.28 rows=2 width=0) (actual time=0.003..0.003 rows=0 loops=28876)
Index Cond: (parent_id = t.id)
-> Bitmap Index Scan on index_usability_tests_on_parent_id (cost=0.00..0.28 rows=2 width=0) (actual time=0.001..0.001 rows=0 loops=28876)
Index Cond: (parent_id = t.parent_id)
-> Materialize (cost=4.62..153.63 rows=39 width=4) (actual time=0.001..0.076 rows=70 loops=32098)
-> Bitmap Heap Scan on responses r (cost=4.62..153.44 rows=39 width=4) (actual time=0.053..0.187 rows=70 loops=1)
Recheck Cond: (user_id = 3649)
-> Bitmap Index Scan on index_responses_on_user_id (cost=0.00..4.61 rows=39 width=0) (actual time=0.040..0.040 rows=70 loops=1)
Index Cond: (user_id = 3649)
Total runtime: 5718.592 ms
【问题讨论】:
-
您是否尝试递归查询该表中的层次结构?如果是,那么您需要 CTE。
-
我会考虑尝试将条件拆分为两个查询的联合。我能问一下检查父 ID 是否匹配的目的是什么,这是否只是为了确保您在测试中获得每条记录至少一次?
-
@ChrisProsser 这只是更大查询的一部分,它根据连接表
c的属性进行进一步过滤。单独来看,我可以看到此查询的DISTINCT结果与SELECT id from tests没有什么不同。 -
就像旁注一样,当您过滤以选择表的一小部分时,索引通常有助于提高速度,但当您必须返回表的大部分时不要加快速度.
-
如果询问查询性能,总是显示您的确切 PostgreSQL 版本 (
SELECT version()) 和explain analyze结果。 总是.
标签: sql performance postgresql left-join