Sql-Server

使用 SET @Variable = Field= @Variable + 1 在堆上出現意外更新結果,使用聚集索引修復

  • July 11, 2021

我只是想了解為什麼會發生這種情況,而我的Google搜尋失敗了。我們使用的是 SQL Server 2016 SP1。

情況如下:供應商表通過跟踪每個表的目前值來管理 ID。如果您正在執行插入,則可以呼叫一個函式來返回一個 ID 塊。

所以我們通過使用從真實表中選擇來設置一個臨時表select into(我們正在複製一組數據以使用不同的屬性集重新插入)。

然後我們呼叫該函式並獲取記錄數的新 id(它只返回最大 ID,所以我們做一些數學運算來獲取下一個 id)。

然後我們像這樣更新表:

update #temp set @nextId = Id = @nextId + 1

期望它將為每條記錄增加一併設置ID。

相反,為每 4 條記錄設置相同的 ID,然後它會增加,接下來的 4 條獲得下一個 id,等等。為什麼每 4 條記錄?什麼地方出了錯?

結果

更有趣的是,如果我們在表上放置一個聚集索引,一切都會正常工作。

我確定這與表格堆有關……但不知道為什麼。

連結到計劃

該聲明的文件UPDATE說(強調添加):

在 UPDATE 語句中可以使用變數名來顯示受影響的舊值和新值,但只有在 UPDATE 語句影響單個記錄時才應使用該變數名。

有些人試圖通過對其使用施加越來越大的限制來使這種“古怪的更新”技術可靠地用於多行。事實仍然是,這依賴於觀察到的效果和未記錄的行為,所以你不應該期望它一般工作,或者在未來繼續“工作”。

如果沒有重現腳本或執行計劃,我無法確切地說出您的情況“出了什麼問題”,但最終這並不重要。如果被迫猜測,我會說您的更新在 DOP 4 處執行,並且四個執行緒同時讀取相同的變數值。

建議您改用可靠的解決方案,例如ROW_NUMBER( docs )、IDENTITY functionsequence

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