是什么阻止"从TableName中选择前1*与(nolock)"返回结果?

Bra*_*ore 10 sql locking sql-server-2008

我目前正在运行以下声明

select * into adhoc..san_savedi from dps_san..savedi_record
Run Code Online (Sandbox Code Playgroud)

这花了很长时间,我想看看它走了多远,所以我跑了这个:

select count(*) from adhoc..san_savedi with (nolock)
Run Code Online (Sandbox Code Playgroud)

那并没有及时返回任何东西,所以为了它,我做了这个:

select top 1 * from adhoc..san_savedi with (nolock)
Run Code Online (Sandbox Code Playgroud)

即使这似乎无限期地运行.我可以理解,如果有数百万条记录计数(*)可能需要很长时间,但我不明白为什么选择前1条记录不会立即回来考虑我指定nolock.

在完全公开的名义中,dps_san是一个通过链接服务器从odbc连接中获取的视图.我不认为这会影响为什么我不能退回到第一排但只是把它扔到那里以防我错了.

所以我想知道是什么让该语句不能运行?

编辑:

如上所述,是的dps_san..savedi_record是一个视图.这是它的作用:

select * from DPS_SAN..root.SAVEDI_RECORD
Run Code Online (Sandbox Code Playgroud)

它只不过是一个别名而且没有分组/排序等等所以我不认为这里存在问题,但如果我错了,请赐教.

Mar*_*ith 11

SELECT如果查询NOLOCK实际上没有锁定,它们仍然需要SCH-S在表上进行(模式稳定性)锁定(因为它是一个堆,它也会hobt锁定).

此外,在SELECT甚至可以开始之前,SQL Server必须编译该语句的计划,这也要求它SCH-S在表上锁定.

当您长时间运行的事务通过SELECT ... INTO它创建表时,它SCH-M会在语句完成之前保持不兼容的锁.

您可以通过查看验证这一点sys.dm_os_waiting_tasks ,而 同时封闭期间的周期.

当我在一个连接中尝试以下内容时

BEGIN TRAN

SELECT *
INTO NewT
FROM master..spt_values

/*Remember to rollback/commit this later*/
Run Code Online (Sandbox Code Playgroud)

然后执行(或只是简单地尝试查看估计的执行计划)

SELECT *
FROM NewT
WITH (NOLOCK)
Run Code Online (Sandbox Code Playgroud)

在一秒钟内,阅读查询被阻止.

SELECT wait_type,
       resource_description
FROM sys.dm_os_waiting_tasks
WHERE session_id = <spid_of_waiting_task>
Run Code Online (Sandbox Code Playgroud)

显示等待类型确实SCH_S和阻塞资源SCH-M

wait_type        resource_description
---------------- -------------------------------------------------------------------------------------------------------------------------------
LCK_M_SCH_S      objectlock lockPartition=0 objid=461960722 subresource=FULL dbid=1 id=lock4a8a540 mode=Sch-M associatedObjectId=461960722
Run Code Online (Sandbox Code Playgroud)