今天我花了一个多小时对一个我无法理解的查询计划感到困惑。该查询是一个UPDATE
,它根本不会运行。完全陷入僵局:pg_locks
表明它也没有等待任何东西。现在,我不认为自己是最好或最差的查询计划阅读器,但我发现这一点异常困难。我想知道如何阅读这些内容?是否有 Pg ace 遵循的方法来查明错误?
我打算就如何解决这个问题提出另一个问题,但现在我要专门讨论如何阅读这些类型的计划。
QUERY PLAN
--------------------------------------------------------------------------------------------
Nested Loop Anti Join (cost=47680.88..169413.12 rows=1 width=77)
Join Filter: ((co.fkey_style = v.chrome_styleid) AND (co.name = o.name))
-> Nested Loop (cost=5301.58..31738.10 rows=1 width=81)
-> Hash Join (cost=5301.58..29722.32 rows=229 width=40)
Hash Cond: ((io.lot_id = iv.lot_id) AND ((io.vin)::text = (iv.vin)::text))
-> Seq Scan on options io (cost=0.00..20223.32 rows=23004 width=36)
Filter: (name IS NULL)
-> Hash (cost=4547.33..4547.33 rows=36150 width=24)
-> Seq Scan on vehicles iv (cost=0.00..4547.33 rows=36150 width=24)
Filter: (date_sold IS NULL)
-> Index Scan using options_pkey on options co (cost=0.00..8.79 rows=1 width=49)
Index Cond: ((co.fkey_style = iv.chrome_styleid) AND (co.code = io.code))
-> Hash Join (cost=42379.30..137424.09 rows=16729 width=26)
Hash Cond: ((v.lot_id = o.lot_id) AND ((v.vin)::text = (o.vin)::text))
-> Seq Scan on vehicles v (cost=0.00..4547.33 rows=65233 width=24)
-> Hash (cost=20223.32..20223.32 rows=931332 width=44)
-> Seq Scan on options o (cost=0.00..20223.32 rows=931332 width=44)
(17 rows)
这个查询计划的问题 - 我相信我理解 - 最好的说法可能是RhodiumToad
(他肯定更擅长这一点,所以我敢打赌他的解释会更好)irc://irc.freenode.net/#postgresql
:
哦,该计划可能是灾难性的,该计划的问题是它为每一行运行一个非常昂贵的 hashjoin 问题是来自另一个连接的 rows=1 估计,并且计划者认为可以在内部放置一个非常昂贵的查询估计外部路径仅返回一行的嵌套循环的路径。因为,显然,根据规划者的估计,昂贵的部分只会运行一次,但这在实践中很明显会搞砸,问题是规划者理想地相信自己的估计,规划者需要知道“估计”之间的区别返回 1 行”和“不可能返回超过 1 行”,但目前尚不清楚如何将其合并到现有代码中
他接着说:
它可以影响任何连接,但通常针对子查询的连接是最有可能的
现在,当我阅读这个计划时,我注意到的第一件事是Nested Loop Anti Join
,这有一个成本169,413
(我会坚持上限)。此反连接分解Nested Loop
为成本为的结果和成本为31,738
的结果。现在,,比我知道问题出在 Hash Join 的要大得多。Hash Join
137,424
137,424
31,738
然后我继续EXPLAIN ANALYZE
查询之外的 Hash Join 段。它在 7 秒内执行。我确保 (lot_id, vin) 和 (co.code, and v.code) 上有索引——有。我单独禁用seq_scan
并hashjoin
注意到速度增加不到 2 秒。还不足以解释为什么一个小时后它没有进展。
但是,毕竟我完全错了!是的,这是查询中较慢的部分,但因为rows="1"
位(我认为它在Nested Loop Anti Join
)。这是计划程序错误估计行数的错误(缺乏能力)?我应该如何阅读这个来得出相同的结论RhodiumToad
?
仅仅rows="1"
是这应该触发我弄清楚这一点吗?
我确实VACUUM FULL ANALYZE
在所有涉及的表上运行,这是 Postgresql 8.4。