Sql 是什么阻止了“使用(nolock)从TableName中选择top 1*”返回结果?

Sql 是什么阻止了“使用(nolock)从TableName中选择top 1*”返回结果?,sql,sql-server-2008,locking,Sql,Sql Server 2008,Locking,我目前正在运行以下语句 select * into adhoc..san_savedi from dps_san..savedi_record 这花了很长时间,我想看看有多远,所以我运行了这个: select count(*) from adhoc..san_savedi with (nolock) 这并没有及时返回任何内容,所以我做了如下操作: select top 1 * from adhoc..san_savedi with (nolock) 即使这样,似乎也会无限期地延续下去。我可

我目前正在运行以下语句

select * into adhoc..san_savedi from dps_san..savedi_record
这花了很长时间,我想看看有多远,所以我运行了这个:

select count(*) from adhoc..san_savedi with (nolock)
这并没有及时返回任何内容,所以我做了如下操作:

select top 1 * from adhoc..san_savedi with (nolock)
即使这样,似乎也会无限期地延续下去。我可以理解,如果有数百万条记录,那么计数*可能需要很长时间,但考虑到我指定了nolock,我不理解为什么选择前1条记录不会立即返回

以完全公开的名义,dps_san是一种通过链接服务器从odbc连接提取数据的视图。我不认为这会影响我为什么不能返回第一排,但如果我错了就把它扔出去

我想知道是什么阻止了这句话

编辑:

如上所述,是的,dps_san..savedi_记录是一个视图。它的作用如下:

select * from DPS_SAN..root.SAVEDI_RECORD

它只不过是一个别名,没有分组/排序等功能,所以我认为问题不在这里,但如果我错了,请告诉我。

很可能没有锁。。。如果dps_san..savedi_record是一个视图,那么它可能需要很长时间才能执行,因为它可能在访问表时不使用索引,也可能在对数百万条记录进行排序,或者出于任何原因。然后,你的查询,即使是一个简单的顶部或计数,只会和视图的执行速度一样快。dps_san..savedi_记录是否为视图?如果是这样,获取数据可能需要很长时间。我能想到的另一件事是,您试图使用select into语法创建一个临时表,这是一个坏主意。选择*进入。。。语法将在选择期间锁定tempdb

如果使用该语法创建表,则有一个变通方法。首先,通过在初始语句末尾抛出where 1=0来创建表:

select * into ... from ... where 1=0
这将首先创建一个表,该表很快,允许您插入,因为该表现在已经存在,在查询期间不会受到锁定tempdb的惩罚。

使用NOLOCK的SELECT查询实际上不接受任何锁,它们仍然需要表上的SCH-S模式稳定性锁

此外,在SELECT开始之前,SQL Server必须为该语句编译一个计划,这也要求它对表进行SCH-S锁定

当长时间运行的事务通过选择创建表时。。。在语句完成之前,INTO将在其上保留一个不兼容的SCH-M锁

您可以通过在阻塞期间查看sys.dm_os_waiting_tasks来验证这一点

当我在一个连接中尝试以下操作时

BEGIN TRAN

SELECT *
INTO NewT
FROM master..spt_values

/*Remember to rollback/commit this later*/
然后执行或只是尝试查看估计的执行计划

SELECT *
FROM NewT
WITH (NOLOCK)
在一秒钟内,读取查询被阻止

SELECT wait_type,
       resource_description
FROM sys.dm_os_waiting_tasks
WHERE session_id = <spid_of_waiting_task>
查找正在执行“选择到”操作的会话\u id:

这应该让您知道另一个会话是否正在阻止select into,或者它是否具有导致问题的等待类型


您可以在另一个窗口中为尝试执行选择操作的会话重复该过程。我怀疑Martin是对的,我先前关于模式锁的评论是相关的。

视图的作用是什么?如果它执行GROUP BY、ORDER BY或使用聚合函数,则可能是选择前1行的成本几乎与选择所有行的成本相同。您确定SELECT INTO已将一行写入磁盘吗?可能它仍处于模式锁定模式,因为它仍在等待ODBC从链接连接中传递第一行。@AaronBertrand不,我不确定。不过,我可以打开另一个查询窗口,从dps_san中选择记录。保存我想要的所有记录并获得结果,因此,如果到现在为止它还没有写入任何结果,这将是很奇怪的。已经2个多小时了。@AaronBertrand您是对的,先生,感谢您为我解决了这个问题。我忘了它只能用于创建表。谢谢,我来试一试。选择是针对正在填充的表,而不是视图。请参阅我的编辑。视图只选择*。没有分组/排序/或任何会导致它在返回结果或类似内容之前需要扫描整个表的内容。@AaronBertrand我想他说的和你建议的一样,可能还没有时间插入任何记录。@AaronBertrand-谢谢,英国人可以使用think While!这并不意味着我一定要喜欢它。英国人也可以使用while,对吗-@阿伦伯特朗——事实上,对我来说,while听起来也不错。我计划扩展我的答案,所以我将在同一时间重新讨论它!只是给你一个艰难的时刻。我对while有一个看法,但这并不妨碍我理解你-@马丁史密斯:你的回答很好,但我只给了你一个+1,因为我认为s应该是r。
wait_type        resource_description
---------------- -------------------------------------------------------------------------------------------------------------------------------
LCK_M_SCH_S      objectlock lockPartition=0 objid=461960722 subresource=FULL dbid=1 id=lock4a8a540 mode=Sch-M associatedObjectId=461960722
SELECT r.session_id, r.blocking_session_id, r.wait_type, r.wait_time
  FROM sys.dm_exec_requests AS r
  CROSS APPLY sys.dm_exec_sql_text(r.plan_handle) AS t
  WHERE t.[text] LIKE '%select%into%adhoc..san_savedi%';