Sql-Server

什麼可能導致單個表中似乎缺少數據

  • November 28, 2019

我有一種情況,好像我在單個表中失去了數據。

我有一個帶有日誌中間件的 .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_TRANSACTIONSOFF伺服器上,我沒有XACT_ABORT在查詢中使用。如果我不執行一個事務回滾怎麼會發生BEGIN TRANSACTIONIMPLICIT_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

DB<>小提琴

但是,如果我不執行 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 行“消失”

在此處輸入圖像描述

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