SQL 中是否可能出現競爭條件?
我想了解 SQL 標準對並行查詢和競爭條件的規定。如果沒有標準,那麼我會對流行數據庫採用的方法感興趣。
我知道 2+ 只讀查詢可以並行執行,但是讀/寫或寫/寫對也可以並行執行嗎?
例如,假設一個簡單的聚合,例如
SELECT AVG(col1) FROM tbl;
在執行的同時,我將發出一個
INSERT INTO tbl (col1) VALUES (3);
是在執行
INSERT
時執行SELECT
還是會INSERT
被阻塞直到執行完成?換句話說,在 SQL 中是否可能出現競爭條件?
此外,我希望能討論一下在這種情況下如何使用行鎖、頁鎖和表鎖。
謝謝
根據 SQL 標準,單個 SQL 查詢會看到它所操作的表的一致狀態。所以它在執行時一定看不到任何變化。但並非所有 DBMS 產品都完全符合這一要求(尤其是那些允許臟讀的產品)。例如 Postgres 或 Oracle
INSERT
在SELECT
執行時不會阻塞(反之亦然)。但是不同的 DBMS 在這種情況下的行為會有所不同,具體取決於它們的配置。-沒有名字的馬
SQL 標準對並發性的定義是事務隔離級別的定義。根據您選擇哪一個,您可以獲得一定的保證。我不會引用標準,因為這個答案應該是可讀的,但這是對定義的解釋:
READ UNCOMMITTED
: 沒有保證。READ COMMITTED
:保證您不會得到任何臟讀,即您不會看到尚未送出的事務中的數據。REPEATABLE READ
:除上述之外,保證您不會遇到不可重複讀取,即,如果您在事務中第二次執行相同的查詢,則不會有任何結果行被並發事務刪除或修改。SERIALIZABLE
:多個事務的並發執行永遠不會產生與相同事務的某個串列執行不同的結果。這意味著您可以避免幻讀,即在一個事務中第二次執行同一查詢期間出現的新行。
你會注意到除了最後一個定義之外的所有定義都是否定的,也就是說,你不能保證一定的行為。例如,如果您選擇
READ UNCOMMITTED
,則不能保證獲得臟讀(在許多實現中您不會,例如在 PostgreSQL 和 Oracle 中)。SQL 標準規定這
SERIALIZABLE
是預設的事務隔離級別,但許多數據庫READ COMMITTED
預設具有(出於性能原因)。因此,關於競爭條件的問題的答案是:是的,您可以獲得競爭條件,具體取決於您使用的隔離級別。僅當您使用
SERIALIZABLE
時,您才能免受競爭條件的影響。(我應該指出,這不適用於 Oracle,它的SERIALIZABLE
隔離級別不符合其名稱。)一般不能給出如何用鎖實現這個問題的答案,因為它在各種實現之間存在顯著差異。但是,有兩種基本技術:
- **讀鎖:**每次讀取和寫入都需要相互阻塞的鎖。隔離級別越高,佔用的鎖就越多。鎖的確切類型取決於實現。
- **多版本化:**不採取讀鎖,讀寫器互不阻塞。修改後的表行的舊版本被保留用於並發讀取請求,以符合隔離級別的保證。