如何强制合并连接?

Posted

技术标签:

【中文标题】如何强制合并连接?【英文标题】:How to force a merge join? 【发布时间】:2015-02-26 16:32:39 【问题描述】:

我的 postgresql 数据库中有这个查询

UPDATE main_table m 
SET new_prod=false 
FROM reseller_product p
WHERE p.distributor_id=896 
AND p.sku = m.sku 
AND p.reseller_id=8;

而且执行时间太长。我在两个表中的 sku 列上都有索引。使用 EXPLAIN 命令后,我看到刨床使用了 Hash Join。在我看来,Merge Join 在这里会更快。我错了吗 ?或者也许刨床使用了 Merge Join,因为查询有像“p.distributor_id=896”这样的过滤器?

PS sku 类型是字符变化的 (50)

“更新(成本=80414.35..228437.71 行=848460 宽度=212)(实际时间=1582872.917..1582872.917 行=0 循环=1)” “ -> 哈希连接(成本=80414.35..228437.71 行=848460 宽度=212)(实际时间=6906.044..23677.829 行=706328 循环=1)” " 哈希条件: ((p.sku)::text = (m.sku)::text)" “ -> 追加(成本=0.00..96319.53 行=1067877 宽度=20)(实际时间=0.909..7426.880 行=808287 循环=1)” “ -> 使用 res_prod_reseller_id 对 reseller_product p 进行索引扫描(成本=0.00..8.74 行=1 宽度=20)(实际时间=0.729..0.729 行=0 循环=1)” " 索引条件:(reseller_id = 8)" “过滤器:(distributor_id = 896)” “ -> reseller_product_8 p 上的 Seq 扫描(成本=0.00..96310.79 行=1067876 宽度=20)(实际时间=0.168..3850.121 行=808287 循环=1)” " 过滤器:((distributor_id = 896) AND (reseller_id = 8))" “ -> 哈希(成本=45779.60..45779.60 行=848460 宽度=202)(实际时间=6897.658..6897.658 行=709948 循环=1)” “存储桶:1024 批次:256 内存使用量:417kB” “ -> 对 main_table m 进行 Seq 扫描(成本=0.00..45779.60 行=848460 宽度=202)(实际时间=0.926..2770.997 行=709948 循环=1)”

【问题讨论】:

如果你发布EXPLAIN计划会更好 explain.depesz.com/s/z1m 在这里 能否请您也发布两个表定义? 【参考方案1】:

您的计划提到您要更新近百万行,selecting 数据需要 23 秒,而 updatingselecting 他们需要 26 分钟 >。 updating他们是主要问题而不是用于selecting它的计划

当您主要订购您的结果时,最好使用MERGE JOIN。在您的情况下,HASH JOIN 似乎是合适的选择,因为为什么规划者会浪费时间在不需要时订购结果。您仍然可以通过发出“set enable_hashjoin = off”强制规划器使用MERGE JOIN,但这可能会使查询变慢。

我怀疑表上的任何 触发器/索引 正在更新 main_tablemulti-column index's,其中包含 new_prod。我建议您在更新完记录后禁用触发器和/或添加indexes。您的读/写速度还可能取决于考虑您的硬件的其他因素。

【讨论】:

【参考方案2】:

main_tablereseller_product 中的 sku 列在两个表中的类型是否相同?

reseller_product 是否有此顺序的索引?

CREATE INDEX I_reseller_product_1 ON reseller_product (distributor_id,reseller_id,sku);

main_table 是否在 sku 列中有索引?

CREATE INDEX I_main_table_1       ON main_table      (sku);

如果所有问题都是肯定的,试试这个:

UPDATE main_table m 
SET    new_prod = false 
WHERE  EXISTS (SELECT 1 
               FROM   reseller_product p
               WHERE  p.distributor_id = 896 
               AND    p.reseller_id    = 8
               AND    p.sku            = m.sku 
               );

【讨论】:

以上是关于如何强制合并连接?的主要内容,如果未能解决你的问题,请参考以下文章

Git - 如何在所选文件上强制合并冲突和手动合并

如何强制将我在本地拥有的所有内容合并到远程主机中?

强制 Git 在合并期间始终选择较新的版本?

excel两个单元格内容合并不了怎么办?

git 分支合并 强制合并

Git合并与强制覆盖