對可序列化隔離錯誤進行故障診斷 - Amazon Redshift

Amazon Redshift 自 2025 年 11 月 1 日起不再支援建立新的 Python UDF。如果您想要使用 Python UDF,請在該日期之前建立 UDF。現有 Python UDF 將繼續正常運作。如需詳細資訊,請參閱部落格文章

對可序列化隔離錯誤進行故障診斷

錯誤:1023 詳細資訊:Redshift 中的資料表上發生可序列化隔離違規

當 Amazon Redshift 偵測到可序列化隔離錯誤時,您會看到錯誤訊息,如下所示。

ERROR:1023 DETAIL: Serializable isolation violation on table in Redshift

若要解決可序列化隔離錯誤,您可以嘗試以下方法:

  • 重試已取消的交易。

    Amazon Redshift 偵測到並行工作負載不可序列化。其表明應用程序邏輯中有差距,此問題通常可以透過重試遇到錯誤的交易來解決。如果問題仍然存在,請嘗試使用其他方法。

  • 將任何無須位於同一不可分割交易中的操作,移到交易之外。

    當兩個交易中的個別操作以可能影響另一個交易結果的方式交叉參考時,適用此方法。例如,以下兩個工作階段各自啟動一個交易。

    Session1_Redshift=# begin;
    Session2_Redshift=# begin;

    每個交易中 SELECT 陳述式的結果,可能會受到另一個交易中 INSERT 陳述式的影響。換句話說,假設您以任何順序,依序執行以下陳述式。在每種情況下,結果都是其中一個 SELECT 陳述式會比同時執行全部交易多傳回一行。依序執行的操作中,沒有任何執行順序可以產生與並行執行相同的結果。因此,最後一個執行的操作會導致可序列化隔離錯誤。

    Session1_Redshift=# select * from tab1; Session1_Redshift=# insert into tab2 values (1);
    Session2_Redshift=# insert into tab1 values (1); Session2_Redshift=# select * from tab2;

    在許多情況下,SELECT 陳述式的結果並不重要。換句話說,交易中操作的不可分割性並不重要。在這些情況下,將 SELECT 陳述式移到交易之外,如以下範例所示。

    Session1_Redshift=# begin; Session1_Redshift=# insert into tab1 values (1) Session1_Redshift=# end; Session1_Redshift=# select * from tab2;
    Session2_Redshift # select * from tab1; Session2_Redshift=# begin; Session2_Redshift=# insert into tab2 values (1) Session2_Redshift=# end;

    在這些範例中,交易中沒有交叉參考。兩個 INSERT 陳述式不會互相影響。在這些範例中,至少有一個順序,可讓交易依序執行並產生與並行執行相同的結果。這表示交易是可序列化的。

  • 請透過鎖定每個工作階段中的所有資料表來強制序列化。

    LOCK 命令能封鎖可能導致可序列化隔離錯誤的操作。使用 LOCK 命令時,請務必執行以下操作:

    • 鎖定受交易影響的所有資料表,包括受交易內部唯讀 SELECT 陳述式影響的資料表。

    • 無論操作的執行順序為何,均以相同的順序鎖定資料表。

    • 在交易開頭,執行任何操作之前,先鎖定所有資料表。

  • 對並行交易使用快照隔離

    使用 ALTER DATABASE 命令搭配快照隔離。若要深入了解 ALTER DATABASE 的 SNAPSHOT 參數,請參閱 參數

錯誤:1018 詳細資訊:關聯不存在

當您在不同的工作階段中執行並行 Amazon Redshift 操作時,您會看到類似如下所示的錯誤訊息。

ERROR: 1018 DETAIL: Relation does not exist.

Amazon Redshift 中的交易會遵循快照隔離。交易開始後,Amazon Redshift 會擷取資料庫的快照。對於交易的整個生命週期,交易會根據快照中反映的資料庫狀態操作。如果交易從快照集中不存在的資料表進行讀取,則會擲回先前顯示的 1018 錯誤訊息。即使另一個並行交易在交易擷取快照集後建立資料表,交易也無法從新建立的資料表中進行讀取。

為了解決此序列化隔離錯誤,您可以嘗試將交易的開始移至您知道該資料表存在的位置。

如果該資料表是由另一個交易建立,則這一個位置點應至少在已遞交該交易之後。此外,請確定沒有遞交任何可能捨棄資料表的並行交易。

session1 = # BEGIN; session1 = # DROP TABLE A; session1 = # COMMIT;
session2 = # BEGIN;
session3 = # BEGIN; session3 = # CREATE TABLE A (id INT); session3 = # COMMIT;
session2 = # SELECT * FROM A;

session2 執行為讀取操作的最後一個操作會導致可序列化隔離錯誤。當 session2 擷取快照集,而資料表已被遞交的 session1 捨棄時,就會發生這個錯誤。換句話說,即使並行的 session3 已經建立資料表,但 session2 仍看不到該資料表,因為其不在快照中。

若要解決此錯誤,您可以按照下方式重新排序工作階段。

session1 = # BEGIN; session1 = # DROP TABLE A; session1 = # COMMIT;
session3 = # BEGIN; session3 = # CREATE TABLE A (id INT); session3 = # COMMIT;
session2 = # BEGIN; session2 = # SELECT * FROM A;

現在,當 session2 擷取其快照時,session3 已經遞交,且該資料表位於資料庫中。Session2 可以從資料表中讀取而不會出現任何錯誤。