是否使用 nolock 块写入器从堆(没有聚集索引的表)中选择数据?

var*_*ble 3 sql-server locking

我尝试复制此处给出的场景: https: //www.sqlskills.com/blogs/paul/the-curious-case-of-the-bulk_operation-lock-during-a-heap-nolock-scan/

创建了 2 个表 - table1 带有聚集索引,table2 没有任何索引。

当我在 table1 上编写选择查询时with (lock),会应用 Sch-S 锁。同样,当我在 table2 上编写相同的查询时,也有一个 Sch-S 锁。

这两种情况都应用了 S 锁,如上面的链接所示。

要检查锁,我使用以下查询:

SELECT * FROM sys.dm_tran_locks
  WHERE resource_database_id = DB_ID()
  AND resource_associated_entity_id = OBJECT_ID(N'dbo.table1');
Run Code Online (Sandbox Code Playgroud)

是否使用 nolock 块写入器从堆(没有聚集索引的表)中选择数据?

Dav*_*oft 5

这对我有用。如果您在表扫描之前刷新页面缓存以减慢速度,这会有所帮助。例如

dbcc dropcleanbuffers
go
select avg(somecol) ap
from someheap with (nolock)
Run Code Online (Sandbox Code Playgroud)

并检查查询计划以确保您进行无序表扫描。

观察快速事物的另一个技巧是引入一个浪费时间的标量值函数,例如:

create or alter function dbo.delay(@ms int)
returns int as
begin
   declare @start datetime2 = sysdatetime()
   while datediff(ms,@start,sysdatetime()) < @ms
   begin
     declare @h bigint = checksum(0x29374190273401923470912384709123)
   end
   return @ms
end
Run Code Online (Sandbox Code Playgroud)

因此,只要您有流式传输计划,您就可以按照您想要的速度进行扫描。

在 AdventureWorksDW 中,我创建了一个像这样的大堆

select top 25000000 s.* 
into someheap 
from FactInternetSales s,  FactInternetSales s2
Run Code Online (Sandbox Code Playgroud)

然后跑了

dbcc dropcleanbuffers
go
select avg(UnitPrice) ap
from someheap with (nolock)
Run Code Online (Sandbox Code Playgroud)

需要足够长的时间才能切换并运行

SELECT
    [resource_type],
    [resource_subtype],
    [resource_associated_entity_id],
    [request_mode]
FROM sys.dm_tran_locks
WHERE
    [resource_type] != N'DATABASE';
Run Code Online (Sandbox Code Playgroud)

并查看 BULK_OPERATION 锁

在此输入图像描述