我正在运行Postgres 12。我有一个这样的解释计划:
Sort (cost=87.71..88.75 rows=418 width=40)
Sort Key: language.name DESC
-> Hash Join (cost=1.14..69.51 rows=418 width=40)
Hash Cond: (film.language_id = language.language_id)
-> Seq Scan on film (cost=0.00..66.50 rows=418 width=21)
Filter: (rating = ANY ('{R,PG-13}'::mpaa_rating[]))
-> Hash (cost=1.06..1.06 rows=6 width=25)
-> Seq Scan on language (cost=0.00..1.06 rows=6 width=25)
据我了解,启动成本等于 0 的节点将是首先运行的节点,因此这 2 个节点并行运行:
胶片上的顺序扫描(成本=0.00..66.50行=418宽度=21(
按语言扫描(成本=0.00..1.06行=6宽度=25(
然后运行此节点:哈希(成本=1.06..1.06行=6宽度=25(。
然后这个节点:哈希连接(成本=1.14..69.51行=418宽度=40(
最后:排序(成本=87.71..88.75 行=418 宽度=40(
但是,根据这篇文章: https://thoughtbot.com/blog/reading-an-explain-analyze-query-plan 执行顺序应该是:
按语言扫描(成本=0.00..1.06行=6宽度=25(
哈希(成本 = 1.06..1.06 行 = 6 宽度 = 25(
胶片上的顺序扫描(成本=0.00..66.50行=418宽度=21(
哈希联接(成本 = 1.14..69.51 行 = 418 宽度 = 40(
排序(成本=87.71..88.75 行=418 宽度=40(
那么哪个是正确的答案呢?我是否误解了执行顺序?
顺序如下:
-
language
上的顺序扫描 -
同时,从结果构建哈希表(哈希表在完成之前无法使用,因此其启动成本等于扫描的总成本(
-
film
上的顺序扫描 -
同时,哈希连接是通过探测哈希表来计算的
-
一旦连接完成,就可以开始排序
据我了解,启动成本等于 0 的节点将是首先运行的节点,
这是不正确的。 启动成本是交付第一行之前的估计成本(直到它收到第一行(。 它包括其任何子节点的启动时间,但不包括任何非子节点的启动时间,即使它在非子节点首先执行其他操作之前无法执行任何工作。
所以这两个节点并行运行:
您的计划不显示任何并行行为。 它们是插层的(我从化学中的话,如果有 CS 术语,我没有(,但不像在多个 CPU 上运行那样并行。
我认为你试图读得太多了。 遗嘱执行人的确切细节仅与计划者的确切细节松散地联系在一起。
但是对于执行者来说,它是这样的:
- 在电影上启动 seq 罐。
- 一旦找到通过过滤器的行,暂停此扫描并完成对语言的扫描,对结果进行哈希处理 假设哈希表适合内存,完成电影中
- 第一行的哈希连接,如果找到匹配项,则将其馈送到排序中,然后完成电影中的其余行将它们匹配到哈希表并将它们也提供给排序。
每当一行被喂入排序时,它都必须处理它。 这可以像插入缓冲区一样简单,也可以对缓冲区中当前的所有内容进行排序并将整个内容写入磁盘。
前两步出现怪异小舞的原因是,如果找不到"电影"中的任何内容,就没有理由阅读和散列"语言"。 我认为策划者根本不承认这种舞蹈。