本文為英文版的機器翻譯版本,如內容有任何歧義或不一致之處,概以英文版為準。
可序列化隔離
有些應用程式需要的不僅僅是並行查詢和載入,還有並行寫入多個資料表或相同的資料表的能力。在此情況下,並行表示重疊,而不是排程在完全相同的時間執行。如果第二個交易在第一個認可之前開始,則會把兩個交易會視為並行。並行操作可能源自受相同使用者或不同使用者控制的不同工作階段。
注意
Amazon Redshift 支援預設的自動遞交行為,其中每個單獨執行SQL命令都會個別遞交。如果您在交易區塊中含括一組命令 (由 BEGIN 和 END 陳述式定義),該區塊會以一個交易的形式認可,因此您可以在必要時加以復原。此行為的例外是 TRUNCATE和 VACUUM命令,其會自動遞交目前交易中所有未完成的變更。
有些SQL用戶端會自動發出 BEGIN 和 COMMIT 命令,因此用戶端會控制一組陳述式是作為交易執行,還是每個個別陳述式都會作為自己的交易執行。請查看您正在使用的界面文件。例如,使用 Amazon Redshift JDBC驅動程式時,JDBCPreparedStatement
具有查詢字串的 包含多個 (以分號分隔) SQL命令,會以單一交易方式執行所有陳述式。相反地,如果您使用 SQL Workbench/J 並設定 AUTO COMMIT ON,則如果您執行多個陳述式,則每個陳述式都會作為自己的交易執行。
Amazon Redshift 中是使用資料表上的寫入鎖定及可序列化隔離的原則,以保護的方式支援並行寫入操作。可序列化隔離可維持對資料表執行的交易對該資料表執行的唯一交易的錯覺。例如,兩個並行執行的交易,T1 和 T2,必須產生與下列至少一項相同的結果:
-
T1 和 T2 會依照該順序循序執行。
-
T2 和 T1 會依照該順序循序執行。
並行交易彼此看不見對方;它們無法偵測彼此的變更。每個並行交易將在交易開始時建立資料庫的快照。在交易中建立資料庫快照時,會針對大多數SELECT陳述式、 COPY、UPDATE、 DELETE INSERT和 等DML命令TRUNCATE,以及下列DDL命令的第一次出現:
-
ALTER TABLE (新增或捨棄資料欄)
-
CREATE TABLE
-
DROP TABLE
-
TRUNCATE TABLE
如果並行交易的任何序列執行會產生與其並行執行相同的結果,這些交易會被視為「可序列化」並且可安全地執行。如果這些交易中沒有任何序列執行會產生相同的結果,系統會停止和還原所執行陳述式可能破壞序列化可行性的交易。
系統目錄表 (PG) 和其他 Amazon Redshift 系統資料表 (STL 和 STV) 不會鎖定在交易中。因此,在提交任何並行交易時,即可看到從 DDL 和 TRUNCATE 操作產生的資料庫物件變更。
例如,假設當兩個並行交易 T1 和 T2 開始時,資料表 A 存在於資料庫。假設 T2 透過從 PG_TABLES 目錄資料表中選取 傳回資料表清單。然後 T1 捨棄資料表 A 並遞交,然後 T2 再次列出資料表。資料表 A 現在不會再出現在清單中。如果 T2 嘗試查詢已捨棄的資料表,Amazon Redshift 會傳回「關聯不存在」錯誤。傳回資料表的清單至 T2 或檢查資料表 A 存在的類別查詢,不會受限於與對使用者資料表執行的相同隔離規則。
對這些資料表更新的交易會在讀取已認可隔離模式中執行。PG 字首類別資料表不支援快照隔離。
系統資料表和類別資料表的可序列化隔離
資料庫快照也會在交易中建立,用於參考使用者建立資料表或 Amazon Redshift 系統資料表 (STL 或 ) 的任何SELECT查詢STV。SELECT 未參考任何資料表的查詢不會建立新的交易資料庫快照。INSERT、 DELETE和 UPDATE陳述式僅在系統目錄資料表 (PG) 上運作,也不會建立新的交易資料庫快照。
如何修正可序列化隔離錯誤
ERROR:1023 DETAIL: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 的 SNAPSHOT 參數的詳細資訊DATABASE,請參閱 參數。
ERROR:1018DETAIL:關聯不存在
當您在不同的工作階段中執行並行 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 可以從資料表中讀取而不會出現任何錯誤。