簡體   English   中英

PostgreSQL 9.6 - 插入沖突后更新返回的地方

[英]PostgreSQL 9.6 - INSERT ON CONFLICT DO UPDATE WHERE RETURNING

我創建並自動化了一個自定義工作流程,以便熱切地同步一系列物化視圖。 在嘗試了幾種不同的方法(針對一對多關系)后,我發現最可靠的同步工作流程是刪除可能已受影響的所有記錄,然后插入新記錄。

DELETE FROM
    some_materialized_view
WHERE
    set_of_records_key = some_value;

INSERT INTO
    some_materialized_view
SELECT
    *
FROM
    some_query_generating_some_materialized_view;

注意:some_query_generating_some_materialized_view是一個復雜的讀取操作,需要執行非常少量的資源。 另外,some_materialized_view被多個外鍵和其他約束嚴重索引。

這感覺非常沉重。 此工作流程帶有過多的刪除和插入操作,這些操作通常是不必要的,因為某些已刪除的記錄可能相同或類似,足以成為UPDATE的候選者。

我更喜歡以下內容:

DELETE FROM
    some_materialized_view
USING
    (
        SELECT
            unique_key
        FROM
            some_materialized_view
        WHERE
            set_of_records_key = some_value

        EXCEPT
        INSERT INTO
            some_materialized_view
        SELECT
            *
        FROM
            some_query_generating_some_materialized_view
        ON CONFLICT (...) DO UPDATE
        SET 
            foo = EXCLUDED.foo,
            bar = EXCLUDED.bar,
            ...
        WHERE
            some_materialized_view <> EXCLUDED
        RETURNING
            unique_key
    ) AS sub_query
WHERE
    some_materialized_view.unique_key = sub_query.unique_key;

問題出在ON CONFLICT ... DO UPDATE ... WHERE ... RETURNING子句中。

正如這個問題所述: 如何在PostgreSQL中使用RETURNING和ON CONFLICT?

RETURNING子句僅返回受影響的記錄。 因此,不會返回未受影響的記錄,因此(在上面的示例中)不恰當地刪除了。

似乎讓RETURNING實際返回所有記錄的唯一方法是通過刪除WHERE some_materialized_view <> EXCLUDED子句來不必要地更新相同的記錄,或者在另一個EXCEPT子句中再次運行some_query_generating_some_materialized_view ...這兩個選項也不理想。

那么,我錯過了什么? 還有其他選擇嗎? 如果不是, 通常情況下 ,是否優先在不必要的UPDATE上執行復雜的,資源密集的讀取操作(記住相關的索引維護和檢查約束)?

注意:我不包括EXPLAIN ANALYZE結果,因為這不是特定於單個查詢,而是一般的問題。 為了可維護性和健全性,該項目需要保持一致,並且這種技術多次使用不同結構和用例的表(一些讀重,另一些寫重)。

  • 偽代碼(我不喜歡偽代碼)
  • 展示鏈式CTE
  • 忽略鎖定,序列化和比賽。
  • (和問題的語義/上下文)

WITH fresh AS ( -- workhorse: Called only and exactly once
        SELECT <keyfields> -- *
        FROM some_query_generating_some_materialized_view
        )
,upd AS ( -- update existing rows
        UPDATE some_materialized_view mv
        SET foo = fr.foo, bar = fr.bar
        FROM fresh fr
        WHERE mv.<keyfields = fr.<keyfields>
        RETURNING mv.<keyfields>
        )
/* 
, del AS ( 
        no deletes ???
        )
 */
        -- insert non existing rows.
INSERT INTO some_materialized_view mv ( <targetfields> )
SELECT fr.<srcfields>
FROM fresh fr
WHERE NOT EXISTS (
        SELECT *
        FROM upd nx
        WHERE nx.<keyfields> = fr.<keyfields>
        );

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM