如何强制合并连接?
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 秒,而 updating
和 selecting
他们需要 26 分钟 >。 updating
他们是主要问题而不是用于selecting
它的计划
当您主要订购您的结果时,最好使用MERGE JOIN
。在您的情况下,HASH JOIN
似乎是合适的选择,因为为什么规划者会浪费时间在不需要时订购结果。您仍然可以通过发出“set enable_hashjoin = off”强制规划器使用MERGE JOIN
,但这可能会使查询变慢。
我怀疑表上的任何 触发器/索引 正在更新 main_table
或 multi-column index's
,其中包含 new_prod
。我建议您在更新完记录后禁用触发器和/或添加indexes
。您的读/写速度还可能取决于考虑您的硬件的其他因素。
【讨论】:
【参考方案2】:main_table
和 reseller_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
);
【讨论】:
以上是关于如何强制合并连接?的主要内容,如果未能解决你的问题,请参考以下文章