Sql-Server
為什麼sql server 等待確認?
我有一個經常請求一大組行的應用程序
$$ about 20K $$從 sql 視圖來看,在其他應用程序無法更新數據來源的表的同時,更新查詢被其他應用程序的選擇阻塞。 等待程式碼是“ASYNC_NETWORK_IO”,我發現它被描述為我正在發生的事情,我引用:
這通常是 SQL Server 等待客戶端完成使用數據的地方。可能是客戶端請求了非常大量的數據,或者只是因為糟糕的程式而消耗它的速度非常慢。
客戶端通常一次處理一行,而不是在客戶端記憶體數據並立即向 SQL Server 確認。
我的問題是為什麼 sql server 等待客戶端完成處理該選擇作業,然後才允許在表上發生更新?這是我可以更改的設置或配置嗎?
SQL Server 預設遵循 ACID 數據庫規則。ACID 中的 A 代表 atomic,意思是整個事務發生,或者不發生。ACID 中的 I 代表隔離,這意味著事務彼此隔離,因此一個事務的所有結果對另一個事務都是可見的,或者它們都不可見。這是在 SQL Server 中通過對讀取和寫入使用鎖來實現的(至少在預設情況下是這樣)。讀取 (
SELECT
s) 獲得一個讀取鎖,它可以防止任何寫入 (UPDATE
或INSERT
) 對這些項目(或頁面,或整個表,具體取決於 SQL 的黑魔法鎖升級算法決定)的操作。為了保持隔離,必須保持查詢的讀鎖,直到所有結果都已發送或緩衝。這可以防止寫入獲得它們的鎖(或者更確切地說導致它們等待獲得它們),除非寫入被隔離(參見關於快照隔離的其他答案)。如果沒有,後續寫入的某些結果可能會出現在寫入之前發生的查詢結果中。有幾種解決方案,每個都有權衡:
- 在客戶端緩衝結果(盡快讀取所有行並稍後進行進一步處理)。如果有很多結果,這可能需要大量客戶端記憶體,並且在客戶端完成緩沖之前仍然會阻塞更新(這就是為什麼在任何後續處理之前必須完全緩衝它的原因)。
- 在伺服器端緩衝結果。您可以通過將數據選擇到臨時表中然後返回臨時表而不是原始查詢來執行此操作。這將需要伺服器端記憶體和/或磁碟,因此可能會干擾其他伺服器端操作。
WITH (NOLOCK)
在SELECT
讀操作上使用。這告訴 SQL Server 忽略此讀取的隔離,這意味著當兩行都被同一事務修改時,您可以在結果的開頭獲得一行的原始版本,並在結果的後面獲得另一行的修改版本,並且返回的版本從未同時在數據庫中(即,在查詢期間修改了行,在返回第一行之後但在返回第二行之前)。這個答案的性能成本最低,但通過打破隔離和/或原子性(取決於你如何看待它)產生非 ACID 結果。- 使用快照隔離(請參閱其他答案——我不是快照隔離專家)。請注意,我在快照隔離方面遇到了嚴重的性能問題,並且它也需要大量的伺服器端資源。
可能還有其他解決方案,但這些是最常見的。