在当前环境下,我正在与NOLOCK作战。我听到的一个论点是,锁定的开销会使查询变慢。因此,我设计了一个测试以查看此开销可能是多少。
我发现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上运行(嘈杂,但结果可能相同)
- 设置隔离级别而不是提示(结果相同)
- 关闭表上的锁升级(结果相同)
- 在实际查询计划中检查扫描的实际执行时间(相同结果)
- 重新编译提示(结果相同)
- 只读文件组(结果相同)
最有前途的探索来自删除垃圾变量并使用无结果查询。最初,这表明NOLOCK的速度稍快一些,但是当我向老板展示该演示时,NOLOCK又变慢了。
NOLOCK有什么用,它会减慢使用变量分配进行的扫描的速度?