Sql server Drop过程语句上的死锁

Sql server Drop过程语句上的死锁,sql-server,deadlock,sql-server-2008-r2,Sql Server,Deadlock,Sql Server 2008 R2,我一直致力于通过多线程创建对象来提高数据库(有数千个对象)的安装速度。这导致了在DROP过程语句上造成死锁的不幸行为 单线程部署花费了很长的时间(因为我们讨论的是很多数据库对象。由于模式安装在几百个客户端上,所以改变模式不是一件容易的事)。缓慢的部署阻碍了我们的开发/发布周期 这些脚本包含以下代码 IF OBJECT_ID(N'myProc') IS NOT NULL BEGIN DROP PROCEDURE myProc END GO CREATE PROC.... 第二个脚

我一直致力于通过多线程创建对象来提高数据库(有数千个对象)的安装速度。这导致了在
DROP过程
语句上造成死锁的不幸行为

单线程部署花费了很长的时间(因为我们讨论的是很多数据库对象。由于模式安装在几百个客户端上,所以改变模式不是一件容易的事)。缓慢的部署阻碍了我们的开发/发布周期

这些脚本包含以下代码

IF OBJECT_ID(N'myProc') IS NOT NULL
  BEGIN
    DROP PROCEDURE myProc
  END
GO
CREATE PROC....
第二个脚本包含

IF OBJECT_ID(N'myProc2') IS NOT NULL
  BEGIN
    DROP PROCEDURE myProc2
  END
GO
CREATE PROC....
这些程序完全无关。没有依赖性,所以每一个

死锁图如下所示:

<deadlock-list>
 <deadlock victim="process6c3dc8">
  <process-list>
   <process id="process6c3dc8" taskpriority="0" logused="884" waitresource="OBJECT: 25:1949249999:0 " waittime="3834" ownerId="3008593" transactionname="DROPOBJ" lasttranstarted="2011-04-28T16:34:31.503" XDES="0xa882b950" lockMode="Sch-S" schedulerid="3" kpid="2588" status="suspended" spid="59" sbid="0" ecid="0" priority="0" trancount="2" lastbatchstarted="2011-04-28T16:34:31.503" lastbatchcompleted="2011-04-28T16:34:31.503" clientapp=".Net SqlClient Data Provider" hostname="myPc" hostpid="7296" loginname="myLogin" isolationlevel="read committed (2)" xactid="3008593" currentdb="25" lockTimeout="4294967295" clientoption1="671088672" clientoption2="128056">
    <executionStack>
     <frame procname="adhoc" line="4" stmtstart="264" stmtend="352" sqlhandle="0x0200000092ebe0126e0f90268e2a5bf1eaba70a098515cd9">
DROP PROCEDURE myProc2     </frame>
    </executionStack>
    <inputbuf>
IF object_id(N&apos;myProc2&apos;) is not null
BEGIN
  PRINT N&apos;Dropping procedure myProc2 ...&apos;
  DROP PROCEDURE myProc2
END    </inputbuf>
   </process>
   <process id="processaa4242c8" taskpriority="0" logused="5800" waitresource="OBJECT: 25:1965250056:0 " waittime="3834" ownerId="3008596" transactionname="DROPOBJ" lasttranstarted="2011-04-28T16:34:31.503" XDES="0xab493950" lockMode="Sch-S" schedulerid="2" kpid="5768" status="suspended" spid="60" sbid="0" ecid="0" priority="0" trancount="2" lastbatchstarted="2011-04-28T16:34:31.503" lastbatchcompleted="2011-04-28T16:34:31.503" clientapp=".Net SqlClient Data Provider" hostname="myPC" hostpid="8296" loginname="myLogin" isolationlevel="read committed (2)" xactid="3008596" currentdb="25" lockTimeout="4294967295" clientoption1="671088672" clientoption2="128056">
    <executionStack>
     <frame procname="adhoc" line="4" stmtstart="276" stmtend="370" sqlhandle="0x02000000f019293427b8052cc3d5d18be886f958c4b750a1">
DROP PROCEDURE myProc     </frame>
    </executionStack>
    <inputbuf>
IF object_id(N&apos;myProc&apos;) is not null
BEGIN
  PRINT N&apos;Dropping procedure myProc ...&apos;
  DROP PROCEDURE myProc
END    </inputbuf>
   </process>
  </process-list>
  <resource-list>
   <objectlock lockPartition="0" objid="1949249999" subresource="FULL" dbid="25" objectname="1949249999" id="lock87308e00" mode="Sch-M" associatedObjectId="1949249999">
    <owner-list>
     <owner id="processaa4242c8" mode="Sch-M"/>
    </owner-list>
    <waiter-list>
     <waiter id="process6c3dc8" mode="Sch-S" requestType="wait"/>
    </waiter-list>
   </objectlock>
   <objectlock lockPartition="0" objid="1965250056" subresource="FULL" dbid="25" objectname="myDatabase.dbo.myProc2" id="lock878d9e80" mode="Sch-M" associatedObjectId="1965250056">
    <owner-list>
     <owner id="process6c3dc8" mode="Sch-M"/>
    </owner-list>
    <waiter-list>
     <waiter id="processaa4242c8" mode="Sch-S" requestType="wait"/>
    </waiter-list>
   </objectlock>
  </resource-list>
 </deadlock>
</deadlock-list>

删除程序myProc2
如果对象id(N&apos;myProc2&apos;)不为空
开始
打印N&apos;删除程序myProc2…&apos;
删除程序myProc2
结束
删除程序myProc
如果对象id(N&apos;myProc&apos;)不为空
开始
打印N&apos;删除程序myProc…&apos;
删除程序myProc
结束

由于sysobjects表用于存储存储过程(没有双关语),因此对该表的访问似乎非常糟糕。我建议您在一个线程上创建数据库结构,然后小心地用多个线程上的数据填充它。

防止死锁是书架上的一个主题,但作为一个起点:创建一个将对象与其依赖项相关联的多字典。如果您在部署应用程序中使用C#,它可能会启动以下内容:

var  dependencies = new Dictionary<string, HashSet<string>>();  // I recommend that you write a MultiDictionary class to cover situations like this, I've found it very useful

book OKToCreateSproc(string sprocName)
  {
  foreach (string dependency in dependencies[sprocName])
    if (createdObjects.Contains(dependency) == false)
      return false;
  return true;
  }
var dependencies=new Dictionary();//我建议您编写一个多词典类来涵盖这样的情况,我发现它非常有用
book OKToCreateSproc(字符串存储过程名称)
{
foreach(依赖项[sprocName]中的字符串依赖项)
if(createdObjects.Contains(dependency)==false)
返回false;
返回true;
}
请注意,您需要一个线程安全的集合,而且我不相信香草通用字典是安全的。看起来这里已经很好地解决了这个问题:

如果您觉得自己很聪明,您可以通过删除DDL脚本以编程方式填充
依赖项
,但这可能有些过分,除非您有一个非常复杂的数据库


哦,是的,您也可以捕获死锁,将问题存储过程推到队列的末尾,然后稍后再试。粗糙,但有效

通过检查删除、创建或更改过程的不同命令所取出的锁,我相信您可以通过将使用的模式更改为:

IF OBJECT_ID(N'myProc') IS NULL
    EXEC sp_executesql N'Create Proc myProc as RETURN 0'
GO
ALTER PROC myProc 
AS ...
当我查看DROP PROC取出的锁时,我看到:

  • Sch-M锁在resource\u type=“METADATA.AUDIT\u ACTIONS”和resource\u type=“METADATA.PERMISSIONS”上被解除
  • Sch-S锁在存储过程所指的表上取出
  • 所有其他锁都是系统对象上的X或IX锁
当我查看创建过程中使用的锁时,我看到:

  • 在程序本身上取出Sch-M锁

  • 在存储过程所指的表上短暂取出Sch-S锁(发布时引用了
    myProc
    reference
    myProc2
    ,反之亦然?@Daniel这些程序完全不相关。死锁在
    Sch-M
    上,并且
    Sch-S
    锁。对象创建非常慢,是一个瓶颈。这是多线程it的主要驱动因素。因此,如果它们通过
    sysdependens>关联,你会这么说
    删除一个会导致另一个被
    SCH-S
    锁定?啊,实际上可能是另一种情况。他们已经有
    SCH-M
    锁定,正在等待
    SCH-S
    锁定。可能在添加依赖项信息时会被删除?+1当我试图用由于某些原因,并发事务中的h依赖项还没有完全解决死锁问题。OP表示SP是不相关的,因此不太可能通过依赖项发生冲突。捕获和重试是当前的解决方案。但我对此不太满意,因为这会严重污染构建历史。更改过程的模式e drop/create将解决最常见的死锁情况。我将编写一些代码来更改所有的proc脚本并进行测试。感谢您给出明确的答案。(测试后将接受)我们在1300个表上部署了大约12000个过程,例如,在一台20核的服务器上,这将导致一个CPU在很长一段时间内保持100%。多线程将大大缩短此部署时间。(当我设法获得稳定的部署时,我将发布统计信息。)RE:“存储过程所指的对象上没有取出Sch-S锁”根据我的回答,我看不到与您相同的行为。Martin--我在测试引用不同表的进程的情况。根据Filip的问题,在这种情况下,进程是完全不相关的。我可以将我的回答更改为具体的。@Kendra-你知道OP中的死锁图中的资源在元数据上时的样子吗资源?