このクエリは同じ結果を生成するはずですが、CASE
を回避します
-- EXPLAIN ANALYZE
UPDATE table_a a
SET rebuilding_costs = drie.rebuilding_costs
FROM (
SELECT COALESCE(b.address, c.address, d.address) AS address
, COALESCE(b.rebuilding_costs, c.rebuilding_costs, d.rebuilding_costs)
AS rebuilding_costs
FROM table_b b
FULL OUTER JOIN table_c c ON c.address = b.address
AND c.rebuilding_costs BETWEEN 200001 AND 400000
FULL OUTER JOIN table_D d ON d.address = b.address
AND d.rebuilding_costs BETWEEN 400001 AND 600000
WHERE b.rebuilding_costs BETWEEN 100001 AND 200000
) drie
WHERE a.address = drie.address
AND a.rebuilding_costs <> drie.rebuilding_costs -- Avoid useless updates
;
更新:CTEの連鎖セットに基づく同様のアプローチ:
-- --------------------------------
EXPLAIN ANALYZE
WITH cte_b AS (
SELECT b.address, b.rebuilding_costs
FROM table_b b
WHERE b.rebuilding_costs BETWEEN 100001 AND 200000
)
, cte_c AS (
SELECT c.address , c.rebuilding_costs
FROM table_c c
WHERE c.rebuilding_costs BETWEEN 200001 AND 400000
AND NOT EXISTS (SELECT * FROM cte_b WHERE cte_b.address = c.address)
)
, cte_d AS (
SELECT d.address , d.rebuilding_costs
FROM table_d d
WHERE d.rebuilding_costs BETWEEN 400001 AND 600000
AND NOT EXISTS (SELECT * FROM cte_b WHERE cte_b.address = d.address)
AND NOT EXISTS (SELECT * FROM cte_c WHERE cte_c.address = d.address)
)
, cte_bcd AS (
SELECT cte_b.address, cte_b.rebuilding_costs FROM cte_b
UNION ALL SELECT cte_c.address, cte_c.rebuilding_costs FROM cte_c
UNION ALL SELECT cte_d.address, cte_d.rebuilding_costs FROM cte_d
)
UPDATE table_a a
SET rebuilding_costs = cte_bcd.rebuilding_costs
FROM cte_bcd
WHERE a.address = cte_bcd.address
-- avoid useless updates this way:
AND a.rebuilding_costs <> cte_bcd.rebuilding_costs
-- ,or this way:
-- AND cte_bcd.rebuilding_costs IS DISTINCT FROM a.rebuilding_costs
;
UPDATE2:CTEは最適化の障壁として機能するため、遅くなる可能性があります。手っ取り早い方法は、temを(一時的な)VIEWとして書き直し、代わりにこれらを参照することです。これにより、オプティマイザーはクエリのさまざまな部分をサブクエリにシャッフルしたり、サブクエリからシャッフルしたり、これらを組み合わせて再利用したりすることができます。
CREATE TEMP VIEW cte_b AS (
SELECT b.address, b.rebuilding_costs
FROM table_b b
WHERE b.rebuilding_costs BETWEEN 100001 AND 200000
);
CREATE TEMP VIEW cte_c AS (
SELECT c.address , c.rebuilding_costs
FROM table_c c
WHERE c.rebuilding_costs BETWEEN 200001 AND 400000
AND NOT EXISTS (SELECT * FROM cte_b WHERE cte_b.address = c.address)
);
CREATE TEMP VIEW cte_d AS (
SELECT d.address , d.rebuilding_costs
FROM table_d d
WHERE d.rebuilding_costs BETWEEN 400001 AND 600000
AND NOT EXISTS (SELECT * FROM cte_b WHERE cte_b.address = d.address)
AND NOT EXISTS (SELECT * FROM cte_c WHERE cte_c.address = d.address)
);
CREATE TEMP VIEW cte_bcd AS (
SELECT cte_b.address, cte_b.rebuilding_costs FROM cte_b
UNION ALL SELECT cte_c.address, cte_c.rebuilding_costs FROM cte_c
UNION ALL SELECT cte_d.address, cte_d.rebuilding_costs FROM cte_d
);
EXPLAIN -- ANALYZE
UPDATE table_a a
SET rebuilding_costs = cte_bcd.rebuilding_costs
FROM cte_bcd
WHERE a.address = cte_bcd.address
AND a.rebuilding_costs <> cte_bcd.rebuilding_costs -- avoid useless updates
-- AND a.address < 100000
;