10

我目前正在运行以下语句

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_record 是一个视图。这是它的作用:

select * from DPS_SAN..root.SAVEDI_RECORD

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

4

4 回答 4

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*/

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

SELECT *
FROM NewT
WITH (NOLOCK)

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

SELECT wait_type,
       resource_description
FROM sys.dm_os_waiting_tasks
WHERE session_id = <spid_of_waiting_task>

显示等待类型确实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
于 2012-06-08T20:58:29.570 回答
2

很可能没有锁...如果 dps_san..savedi_record 是一个视图,那么它可能需要很长时间才能执行,因为它可能在不使用索引的情况下访问表,或者它可能正在排序数百万记录,或任何原因。然后,您的查询,即使是简单的顶部或计数,也只会与执行该视图一样快。

于 2012-06-08T20:42:56.023 回答
2

这里有几个问题需要考虑。dps_san..savedi_record 是视图吗?如果是这样,获取数据可能需要很长时间。我能想到的另一件事是,您正在尝试使用select into语法创建临时表,这是一个坏主意。select * into ...语法将在选择期间锁定 tempdb。

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

select * into ... from ... where 1=0

这将首先创建表(这很快),这允许您创建表,insert into因为该表现在存在(不会在查询期间锁定 tempdb)。

于 2012-06-08T20:45:03.620 回答
2

找到session_id正在执行的select into

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%';

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

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

于 2012-06-08T21:00:42.977 回答