Sql-Server

為什麼 SQL Server 跟踪標誌 715 的行為與 TABLOCK 查詢提示不同?

  • September 29, 2021

這是我的理解,基於眾多來源(包括這個:https ://techcommunity.microsoft.com/t5/sql-server/migrating-sap-workloads-to-sql-server-just-got-2-5x-faster /ba-p/384910 ) SQL Server 跟踪標誌 715 應該等同於 TABLOCK 查詢提示——不同之處在於 TF715 可以在會話和全域級別設置,而 TABLOCK 只能用作查詢提示。

我的問題是,我已經在 SQL Servers 2016 和 2019 開發版上以簡單的恢復模型進行了測試,無論我使用哪種伺服器,TABLOCK 和 TF715 都得到了不同的結果。TABLOCK 按預期工作,而 TF715 沒有。具體來說,TABLOCK 告訴 SQL Server 為批量操作取出整個表鎖,並最少記錄操作

考慮以下程式碼。這會將 10,000 行插入到堆中。

DROP TABLE IF EXISTS Test
GO

CREATE TABLE Test (t VARCHAR(100))
GO

INSERT INTO Test (t)
SELECT TOP (10000)
   x = ROW_NUMBER() OVER (ORDER BY s1.[object_id])
FROM       sys.columns AS s1
CROSS JOIN sys.columns AS s2

現在,如果您執行下一個程式碼塊,您可以看到它記錄了 10,000 行。

SELECT 
   [Fully Logged Rows] = COUNT_BIG(*) 
FROM sys.fn_dblog(NULL, NULL) AS FD
WHERE
   FD.Operation = N'LOP_INSERT_ROWS'
   AND FD.Context = N'LCX_HEAP'
   AND FD.AllocUnitName = N'dbo.Test';

好的,所以現在如果我們使用 TABLOCK 提示重新執行此操作,您可以看到它變成了最小記錄操作(即,完全記錄的行數 = 0)。

DROP TABLE IF EXISTS Test
GO

CREATE TABLE Test (t VARCHAR(100))
GO

INSERT INTO Test WITH (TABLOCK) (t)
SELECT TOP (10000)
   x = ROW_NUMBER() OVER (ORDER BY s1.[object_id])
FROM       sys.columns AS s1
CROSS JOIN sys.columns AS s2
--0 Fully Logged Rows
SELECT 
   [Fully Logged Rows] = COUNT_BIG(*) 
FROM sys.fn_dblog(NULL, NULL) AS FD
WHERE
   FD.Operation = N'LOP_INSERT_ROWS'
   AND FD.Context = N'LCX_HEAP'
   AND FD.AllocUnitName = N'dbo.Test';

但是,當我嘗試啟用 TF715(並取消 TABLOCK 提示)時,我仍然會得到 10,000 行完全記錄的行,而我希望進行最少記錄的操作。

--Enable TF715 on both a session and global level to cover all bases...
DBCC TRACEON(715)
GO
DBCC TRACEON(715, -1)
GO
DBCC TRACESTATUS
GO

DROP TABLE IF EXISTS Test
GO

CREATE TABLE Test (t VARCHAR(100))
GO

INSERT INTO Test (t)
SELECT TOP (10000)
   x = ROW_NUMBER() OVER (ORDER BY s1.[object_id])
FROM       sys.columns AS s1
CROSS JOIN sys.columns AS s2

--10000 Fully Logged Rows
SELECT 
   [Fully Logged Rows] = COUNT_BIG(*) 
FROM sys.fn_dblog(NULL, NULL) AS FD
WHERE
   FD.Operation = N'LOP_INSERT_ROWS'
   AND FD.Context = N'LCX_HEAP'
   AND FD.AllocUnitName = N'dbo.Test';

DBCC TRACEOFF(715)
GO
DBCC TRACEOFF(715, -1)
GO
DBCC TRACESTATUS
GO

我在看什麼?我不需要重新啟動 SQL Server 來通過 DBCC 啟用 TF,對嗎?

先感謝您。

Parikshit Savjani 引用的文章中的重要引述(強調添加):

TF 715 可以設置在實例級別(全域)或會話級別,這使得 TABLOCK 能夠將批量載入操作批量載入到沒有非聚集索引的堆中。**啟用此跟踪標誌後,在將數據批量複製到沒有非聚集索引的堆中時,批量載入操作預設獲取批量更新 (BU) 鎖。**批量更新 (BU) 鎖允許多個執行緒同時將數據批量載入到同一個表中,同時防止其他不是批量載入數據的程序訪問該表。該行為類似於使用者在執行批量載入時顯式指定 TABLOCK 提示,或者當 sp_tableoption ’table lock on bulk load’ 為給定表打開時,但啟用此 TF 會使此行為預設,而不進行任何查詢更改或數據庫更改。

跟踪標誌 715為在指定 TABLOCK 時支持 BU的批量載入方法啟用 BU 鎖。

INSERT…SELECT外,所有批量載入方法都支持 BU 鎖。

其他批量載入方法的範例包括:

  • SSIS SQL Server 和 OLEDB 數據目標
  • bcp
  • 批量插入
  • ADO.NET 中的 SQLBulkCopy
  • OLE DB 和 SQL Server Native Client ODBC 庫中的 IRowsetFastload

將 TF715 視為始終設置“批量載入表鎖定”可能會有所幫助:

TF 715 的實際效果在很多情況下與指定 TABLOCK類似,但並不完全相同。特別是,BU 鎖確保批量載入程序對錶具有獨占訪問權。

批量導入優化是一組功能。在不同的情況下,您可以獲得一些好處,但不能獲得其他好處。

在您的範例中,您沒有獲得 BU 鎖,因為 INSERT…SELECT 不支持它們。TF715 僅對支持該選項的批量載入方法啟用 BU 鎖定。因此,TF715在您的範例中無效。

當您指定 TABLOCK 時,引擎可以保證批量載入具有對錶的獨占訪問權限,因此允許最少的日誌記錄。


上述討論僅適用於堆表目標。載入聚群表可以受益於相同的底層機制 ( RowsetBulk ) 以及FastLoadContext,它不需要 TABLOCK 或 BU 鎖來啟用最少的日誌記錄。

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