現在の環境でNOLOCKと戦っています。私が聞いた1つの議論は、ロックのオーバーヘッドがクエリの速度を低下させるというものです。そこで、このオーバーヘッドがどれだけあるかを確認するためのテストを考案しました。
NOLOCKが実際にスキャン速度を低下させることを発見しました。
最初は嬉しかったのですが、今は混乱しています。私のテストはどういうわけか無効ですか?NOLOCKは実際にはわずかに高速なスキャンを許可すべきではありませんか?ここで何が起こっているのですか?
これが私のスクリプトです:
USE TestDB
GO
--Create a five-million row table
DROP TABLE IF EXISTS dbo.JustAnotherTable
GO
CREATE TABLE dbo.JustAnotherTable (
ID INT IDENTITY PRIMARY KEY,
notID CHAR(5) NOT NULL )
INSERT dbo.JustAnotherTable
SELECT TOP 5000000 'datas'
FROM sys.all_objects a1
CROSS JOIN sys.all_objects a2
CROSS JOIN sys.all_objects a3
/********************************************/
-----Testing. Run each multiple times--------
/********************************************/
--How fast is a plain select? (I get about 587ms)
DECLARE @trash CHAR(5), @dt DATETIME = SYSDATETIME()
SELECT @trash = notID --trash variable prevents any slowdown from returning data to SSMS
FROM dbo.JustAnotherTable
ORDER BY ID
OPTION (MAXDOP 1)
SELECT DATEDIFF(MILLISECOND,@dt,SYSDATETIME())
----------------------------------------------
--Now how fast is it with NOLOCK? About 640ms for me
DECLARE @trash CHAR(5), @dt DATETIME = SYSDATETIME()
SELECT @trash = notID
FROM dbo.JustAnotherTable (NOLOCK)
ORDER BY ID --would be an allocation order scan without this, breaking the comparison
OPTION (MAXDOP 1)
SELECT DATEDIFF(MILLISECOND,@dt,SYSDATETIME())
私が試したことはうまくいきませんでした:
- 異なるサーバーで実行(同じ結果、サーバーは2016-SP1と2016-SP2で、どちらも静かでした)
- 異なるバージョンのdbfiddle.ukで実行(うるさいが、おそらく同じ結果)
- ヒントの代わりにISOLATION LEVELを設定(同じ結果)
- テーブルのロックエスカレーションをオフにする(同じ結果)
- 実際のクエリプランでのスキャンの実際の実行時間の調査(同じ結果)
- ヒントを再コンパイル(同じ結果)
- 読み取り専用ファイルグループ(同じ結果)
最も有望な調査は、ゴミ箱変数を削除し、結果なしのクエリを使用することです。最初はこれによりNOLOCKがわずかに速くなっていることがわかりましたが、上司にデモを見せたところ、NOLOCKは遅くなりました。
変数の割り当てでスキャンを遅くするのはNOLOCKの何ですか?