Sql-Server

我的 SQL 查詢會使用過時的數據嗎?我該如何預防?

  • December 29, 2019

我有兩個表(SJob& SJobDependent),我需要加入儲存過程中的某些邏輯。它們都有一個列 ( )以一對多的關係job連接它們- 一條記錄對應零個或多個記錄。SJob``SJobDependent

這是我的 SQL 查詢:

-- Return any records that are active and have no unsatisfied dependencies.
SELECT * FROM SJob
LEFT JOIN SJobDependent
   ON SJob.job = SJobDependent.job
   AND SJobDependent.satisfied = 0
WHERE SJobDependent.jobDependentID IS NULL
AND SJob.state = 'active'

以下是 SQL Server Studio 的實際執行計劃

SQL Server Studio 實際執行計劃

由於程式碼的編寫方式:

// Pseudo-code:

// SJob record is added with SJob.state = 'ready'.

// Related SJobDependent record(s) are added.

// SJob record is updated to SJob.state = 'active'.

我擔心 SQL 查詢執行時可能會發生這種情況:

  1. 掃描 SJobDependent。
  2. 已插入 SJobDependent 記錄。
  3. 開始掃描 SJob。SJob.state 已“準備就緒”。
  4. SJob 已更新。這會阻止讀取 SJob?
  5. 結束 SJob 掃描。SJob.state 是“活動的”。

我擔心的問題是我的 SQL 查詢返回SJob在“活動”狀態 ( SJob.state = 'active') 中找到的記錄,但看不到相關SJobDependent記錄。

這個問題會發生嗎,還是我過度分析了 SQL 查詢?

如果這是一個值得擔心的合法問題,我能做些什麼來解決它?我對解決方案持開放態度。

我的一個想法是強制SJobDependent掃描SJob. 這甚至可能嗎?這樣做有什麼影響/後果?

實際執行計劃中顯示的掃描是按特定順序發生的,還是總是隨機呼叫的?

注意:如 AMtwo 的回答中所述,Repeatable Read 隔離級別可能無法解決我的問題,因為它僅在讀取開始時生效。

如果您使用 SQL Server 中的預設隔離級別(已送出讀),那麼您肯定會遇到與讀取不一致有關的各種問題。Paul White 在這裡描述了這些問題。

如果您希望您的讀取查詢讀取與給定時間點的外觀完全一致的數據,我建議您考慮讀取送出快照隔離(RCSI)。使用 RCSI,您的查詢將返回與單個時間點(查詢開始)一致的數據。如果使用者 A 在使用者 B 並發執行更新時啟動SELECT查詢,使用者 A 將讀取“舊”值,因為它將讀取數據的快照,這與查詢的開始是一致的。

RCSI 的關鍵在於它是一個數據庫級別的設置。與未送出的讀取不同,您不能將其設置為會話範圍的設置。在進行更改之前,您必須更全面地考慮此更改。但是一般來說,如果您需要此查詢的一致讀取,您可能需要整個應用程序的一致讀取。

雖然可重複讀取隔離級別看起來很適合解決您的問題,但請注意連結文章中的以下詳細資訊:

可重複讀隔離級別保證數據 在第一次被讀取後在事務的生命週期內不會改變

這意味著數據在被訪問之前仍然可以更改,但在查詢執行期間。它還受到與已送出讀隔離級別相同的一些不一致讀取的影響——尤其是幻像。

引用自:https://dba.stackexchange.com/questions/256321