sql >> データベース >  >> RDS >> PostgreSQL

PostgreSQLで複数のテーブルを使用して大規模な更新を行う

    このクエリは同じ結果を生成するはずですが、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
            ;
    



    1. PHPを介したphpMyAdmin列のエコーjson配列

    2. SQL Server 2008 R2 に格納された XML ドキュメントを XML データ型で読み取る

    3. ORA-29908:補助演算子のプライマリ呼び出しがありません

    4. DATE_ADD()の例– MySQL