什麼可能導致單個表中似乎缺少數據
我有一種情況,好像我在單個表中失去了數據。
我有一個帶有日誌中間件的 .NET Core API。該中間件獲取整個請求和響應並儲存在數據庫中,用於調試和支持目的。除了請求和響應之外,日誌表還包含一個
IDENTITY(1,1)
列(主鍵)和其他各種列。在大約 15 分鐘的持續時間內,似乎有 2798 行已從表中“消失”。主鍵只是從 3561297 跳轉到 3564095。
在同一時間段內,我從該 API 的客戶端獲得了調試日誌,這表明請求期間出現了問題。我的 IIS 日誌指出,在這段時間內導致數據庫訪問的任何請求都需要 30000 到 40000 毫秒才能完成。
奇怪的是,其他表似乎沒有類似的差距。事實上,其他表已經在其中插入和更新了數據,沒有出現問題。所以它似乎不是一個完整的系統崩潰。
通過我的 Google-Fu,我發現
IDENTITY(1,1)
密鑰中的間隙可能是由伺服器重啟引起的——在這種情況下,間隙大約是 1000。但是,在這種情況下,我 100% 確定數據庫尚未重新啟動,但我有這個差距。我嘗試通過插入行並
THROW
在最後添加一條語句來重現此錯誤,但在我的測試環境中無濟於事。我試圖通過在表上添加WAITFOR DELAY
和製作 a來模擬超時TABLOCKX, HOLDLOCK
,同時嘗試通過應用程序進行大量插入。順便說一句,每個數據庫操作都是通過儲存過程完成的。坦率地說,我很難過。有沒有人有任何想法/提示為什麼我在一個表中出現這種明顯的數據失去?或者什麼會導致這樣的主鍵出現巨大的差距?
據我所知,我在日誌中間件 SQL 中沒有事務。並且
IMPLICIT_TRANSACTIONS
在OFF
伺服器上,我沒有XACT_ABORT
在查詢中使用。如果我不執行一個事務回滾怎麼會發生BEGIN TRANSACTION
?IMPLICIT_TRANSACTIONS
如果設置為,我認為 SQL Server 只進行“自動事務”ON
?
在大約 15 分鐘的持續時間內,似乎有 2798 行已從表中“消失”。主鍵只是從 3561297 跳轉到 3564095。在同一時間段內,我從該 API 的客戶端獲得了調試日誌,這表明請求期間出現了問題。我的 IIS 日誌指出,在這段時間內導致數據庫訪問的任何請求都需要 30000 到 40000 毫秒才能完成。
我不認為這些行已經消失了。
您的調試日誌顯示,當間隙發生時,在對數據庫的請求期間出現了問題。如果查詢被中止並回滾,則標識值不會隨之回滾。
另一個例子是應用程序有一個 30 秒的超時視窗。比這更長的查詢將被取消,插入將被回滾。
如前所述,在回滾的情況下,分配的標識值不會被回滾。相反,重試插入時將使用行中的下一個標識值。
插入失敗可能還有其他原因,例如網路失去、插入將被截斷的值、錯誤的數據類型轉換……
下面是一個可重現的範例,顯示了兩個差距:
CREATE TABLE dbo.identitytable(id int identity(1,1), val varchar(255)) INSERT INTO dbo.identitytable(val) VALUES('BLA1'); GO BEGIN TRAN INSERT INTO dbo.identitytable(val) VALUES('BLA2'); ROLLBACK TRAN GO INSERT INTO dbo.identitytable(val) VALUES('BLA3'); GO SELECT * FROM dbo.identitytable; GO INSERT INTO dbo.identitytable(val) VALUES(REPLICATE('B',256)); GO INSERT INTO dbo.identitytable(val) VALUES('BLA5'); SELECT * FROM dbo.identitytable;
最後一個選擇產生的結果有兩個差距:
id val 1 BLA1 3 BLA3 5 BLA5
如果回滾具有多行的插入,則間隙也會更大:
BEGIN TRAN INSERT INTO dbo.identitytable(val) SELECT 'BLA6' FROM master..spt_values; ROLLBACK TRAN INSERT INTO dbo.identitytable(val) VALUES('BLA7'); SELECT * FROM dbo.identitytable;
結果
id val 1 BLA1 3 BLA3 5 BLA5 2546 BLA7
但是,如果我不執行 BEGIN TRANSACTION,怎麼會發生事務回滾?如果 IMPLICIT_TRANSACTIONS 設置為 ON,我認為 TSQL 只進行“自動事務”?
沒有
BEGIN TRANSACTION
或沒有啟用“壞主意”IMPLICIT_TRANSACTION
設置的查詢本身就是自動送出的事務。由於上述原因取消/中止數據修改時,必須在數據庫級別撤消這些更改。這是通過回滾完成的。如果這不存在,您的數據將處於不正確的狀態。
但是,如果我不執行 BEGIN TRANSACTION,怎麼會發生事務回滾?我認為如果 IMPLICIT_TRANSACTIONS 設置為 ON,TSQL 只會進行“自動事務”
不需要顯式交易來擁有
rollback
,例如,任何**constraint
違規**都會rollback
導致整個insert
,這裡有一個小的複制:if object_id('dbo.t') is not null drop table dbto.t; go create table dbo.t(id int identity, col1 int not null); insert into dbo.t (col1) values(1); go insert into dbo.t(col1) select top 2796 row_number() over(order by getdate()) from sys.columns c cross join sys.columns c1 union all select null; go insert into dbo.t (col1) values(2); go select * from dbo.t;
我有
not nullable
列和我insert
導致回滾的第 2796 條記錄,這樣你會發現 2798 行“消失”