Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/sql-server-2005/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/database/9.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Sql server 2005 查询信息时出现死锁\u架构_Sql Server 2005_Tsql - Fatal编程技术网

Sql server 2005 查询信息时出现死锁\u架构

Sql server 2005 查询信息时出现死锁\u架构,sql-server-2005,tsql,Sql Server 2005,Tsql,我有一个进程,它根据已发布元数据层中的更改动态地改变我的SQL2K5表结构 例如,如果需要添加一个新列,并且该表没有依赖项,则步骤如下: 1.使用T-SQL为表中已经存在的任何索引和主键创建脚本[这些脚本包括在下面] 2.放下桌子 3.从具有新列的元层重新创建表 4.执行步骤#1中创建的脚本 5.使用BulkCopy填充表 以上内容通过.NET程序集启动,每天在3个并发流中运行 我在步骤#1中收到一个死锁错误-当我访问信息#模式表以编写索引/键的脚本时。我在这些脚本中使用了带有(NOLOCK)的

我有一个进程,它根据已发布元数据层中的更改动态地改变我的SQL2K5表结构

例如,如果需要添加一个新列,并且该表没有依赖项,则步骤如下: 1.使用T-SQL为表中已经存在的任何索引和主键创建脚本[这些脚本包括在下面] 2.放下桌子 3.从具有新列的元层重新创建表 4.执行步骤#1中创建的脚本 5.使用BulkCopy填充表

以上内容通过.NET程序集启动,每天在3个并发流中运行

我在步骤#1中收到一个死锁错误-当我访问信息#模式表以编写索引/键的脚本时。我在这些脚本中使用了带有(NOLOCK)的提示,认为当这些操作的3个流同时运行时,这应该可以防止任何锁定。一个表只能在一个流中处理(创建或脚本)

还有什么我需要做的吗

非常感谢您的评论

[脚本]

ALTER Procedure [dbo].[s$spScriptPrimaryKeyForTable]
@Tablename varchar(100)
AS 


-- Get all existing primary keys
DECLARE cPK CURSOR FOR
SELECT TABLE_NAME, CONSTRAINT_NAME 
FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS WITH(NOLOCK)
WHERE upper(TABLE_NAME)=upper(@Tablename)
ORDER BY TABLE_NAME

DECLARE @PkTable SYSNAME
DECLARE @PkName SYSNAME

-- Loop through all the primary keys
OPEN cPK
FETCH NEXT FROM cPK INTO @PkTable, @PkName
WHILE (@@FETCH_STATUS = 0)
BEGIN
DECLARE @PKSQL NVARCHAR(4000) SET @PKSQL = ''
SET @PKSQL = 'ALTER TABLE ' + @PkTable + ' ADD CONSTRAINT ' + @PkName + ' PRIMARY KEY CLUSTERED ('

-- Get all columns for the current primary key
DECLARE cPKColumn CURSOR FOR
SELECT COLUMN_NAME 
FROM INFORMATION_SCHEMA.KEY_COLUMN_USAGE WITH(NOLOCK)
WHERE TABLE_NAME = @PkTable AND CONSTRAINT_NAME = @PkName
ORDER BY ORDINAL_POSITION
OPEN cPKColumn

DECLARE @PkColumn SYSNAME
DECLARE @PkFirstColumn BIT SET @PkFirstColumn = 1
-- Loop through all columns and append the sql statement
FETCH NEXT FROM cPKColumn INTO @PkColumn
WHILE (@@FETCH_STATUS = 0)
BEGIN
IF (@PkFirstColumn = 1)
SET @PkFirstColumn = 0
ELSE
SET @PKSQL = @PKSQL + ', '

SET @PKSQL = @PKSQL + @PkColumn

FETCH NEXT FROM cPKColumn INTO @PkColumn
END
CLOSE cPKColumn
DEALLOCATE cPKColumn

SET @PKSQL = @PKSQL + ')'
-- Print the primary key statement
-- PRINT @PKSQL

FETCH NEXT FROM cPK INTO @PkTable, @PkName
END
CLOSE cPK
DEALLOCATE cPK


SELECT ISNULL(@PKSQL,' ')

================

ALTER Procedure [dbo].[s$spScriptIndexesForTable]
@Tablename varchar(100)

AS 

DECLARE @RetVal varchar(4000)
SET @RetVal = ''

-- Get all existing indexes, but NOT the primary keys 
DECLARE cIX CURSOR FOR 
SELECT OBJECT_NAME(SI.Object_ID), SI.Object_ID, SI.Name, SI.Index_ID 
FROM Sys.Indexes SI WITH(NOLOCK)
LEFT JOIN INFORMATION_SCHEMA.TABLE_CONSTRAINTS TC WITH(NOLOCK) ON SI.Name = TC.CONSTRAINT_NAME AND OBJECT_NAME(SI.Object_ID) = TC.TABLE_NAME 
WHERE TC.CONSTRAINT_NAME IS NULL 
AND OBJECTPROPERTY(SI.Object_ID, 'IsUserTable') = 1 
AND upper(OBJECT_NAME(SI.Object_ID))=upper(@Tablename)
ORDER BY OBJECT_NAME(SI.Object_ID), SI.Index_ID 

DECLARE @IxTable SYSNAME 
DECLARE @IxTableID INT 
DECLARE @IxName SYSNAME 
DECLARE @IxID INT 

-- Loop through all indexes 
OPEN cIX 
FETCH NEXT FROM cIX INTO @IxTable, @IxTableID, @IxName, @IxID 
WHILE (@@FETCH_STATUS = 0) 
BEGIN 
DECLARE @IXSQL NVARCHAR(4000) 
--SET @PKSQL = '' 
SET @IXSQL = 'CREATE ' 

-- Check if the index is unique 
IF (INDEXPROPERTY(@IxTableID, @IxName, 'IsUnique') = 1) 
SET @IXSQL = @IXSQL + 'UNIQUE ' 
-- Check if the index is clustered 
IF (INDEXPROPERTY(@IxTableID, @IxName, 'IsClustered') = 1) 
SET @IXSQL = @IXSQL + 'CLUSTERED ' 

SET @IXSQL = @IXSQL + 'INDEX ' + @IxName + ' ON [' + @IxTable + '] (' 

-- Get all columns of the index 
DECLARE cIxColumn CURSOR FOR 
SELECT SC.Name,IC.[is_included_column],IC.is_descending_key 
FROM Sys.Index_Columns IC WITH(NOLOCK)
JOIN Sys.Columns SC WITH(NOLOCK) ON IC.Object_ID = SC.Object_ID AND IC.Column_ID = SC.Column_ID 
WHERE IC.Object_ID = @IxTableID AND Index_ID = @IxID 
ORDER BY IC.Index_Column_ID,IC.is_included_column 

DECLARE @IxColumn SYSNAME 
DECLARE @IxIncl bit 
DECLARE @Desc bit 
DECLARE @IxIsIncl bit set @IxIsIncl = 0 
DECLARE @IxFirstColumn BIT SET @IxFirstColumn = 1 

-- Loop throug all columns of the index and append them to the CREATE statement 
OPEN cIxColumn 
FETCH NEXT FROM cIxColumn INTO @IxColumn, @IxIncl, @Desc 
WHILE (@@FETCH_STATUS = 0) 
BEGIN 

IF (@IxFirstColumn = 1) 
BEGIN 
SET @IxFirstColumn = 0 
END 
ELSE 
BEGIN 
--check to see if it's an included column 
IF ((@IxIsIncl = 0) AND (@IxIncl = 1)) 
BEGIN 
SET @IxIsIncl = 1 
SET @IXSQL = @IXSQL + ') INCLUDE (' 
END 
ELSE 
BEGIN 
SET @IXSQL = @IXSQL + ', ' 
END 
END 

SET @IXSQL = @IXSQL + '[' + @IxColumn + ']' 
--check to see if it's DESC 
IF @Desc = 1 
SET @IXSQL = @IXSQL + ' DESC' 

FETCH NEXT FROM cIxColumn INTO @IxColumn, @IxIncl, @Desc 
END 
CLOSE cIxColumn 
DEALLOCATE cIxColumn 

SET @IXSQL = @IXSQL + ')' 

-- Print out the CREATE statement for the index 
--SELECT 'IXSQL: ' + @IXSQL
IF @RetVal IS NULL
SET @RetVal = ''
--SELECT 'Retval: ' + @RetVal
SET @RetVal = @RetVal + @IXSQL + ' ' 

FETCH NEXT FROM cIX INTO @IxTable, @IxTableID, @IxName, @IxID 
END 

CLOSE cIX 
DEALLOCATE cIX 

SELECT ISNULL(@RetVal,' ')
  • 模式视图中的信息只是那些视图。您无法更新它们,因此它们不太可能导致任何死锁。如果您想确定真正的源代码(我认为这与您的更改有关,或者光标中没有显示的其他代码,或者您在调用这些过程的同时调用的其他代码——因为根据视图进行选择,然后选择变量并不是原因),我建议阅读

  • 尽管(1),我仍然建议使用比信息模式更现代的目录视图。例如,可以从sys.key_约束中导出相同的信息

  • 您正在使用默认的光标选项;你在嵌套游标。如果最终仍然使用游标,则应养成使用资源密集度较低的游标的习惯(例如,本地静态前进只读)

  • 您实际上不需要光标来执行此操作。下面是我将如何重新编写PK表脚本:

    CREATE PROCEDURE dbo.ScriptPKForTable
        @TableName SYSNAME
    AS
    BEGIN
        SET NOCOUNT ON;
    
        DECLARE 
          @pkName    SYSNAME,
          @clustered BIT,
          @object_id INT,
          @sql       NVARCHAR(MAX);
    
        SELECT
          @object_id = OBJECT_ID(UPPER(@TableName));
    
        SELECT
          @pkName = kc.name,
          @clustered = CASE i.[type] 
            WHEN 1 THEN 1 ELSE 0 END
        FROM 
            sys.key_constraints AS kc
        INNER JOIN 
            sys.indexes AS i
            ON kc.parent_object_id = i.[object_id]
            AND kc.unique_index_id = i.index_id
        WHERE
            kc.parent_object_id = @object_id
            AND kc.[type] = 'pk';
    
        SET @sql = N'ALTER TABLE ' + QUOTENAME(@TableName)
          + ' ADD CONSTRAINT ' + @pkName 
          + ' PRIMARY KEY ' + CASE @clustered 
          WHEN 1 THEN 'CLUSTERED' ELSE '' END + ' (';
    
        SELECT
          @sql = @sql + c.name + ','
        FROM 
          sys.index_columns AS ic
        INNER JOIN
          sys.indexes AS i 
          ON ic.index_id = i.index_id
          AND ic.[object_id] = i.[object_id]
        INNER JOIN 
          sys.key_constraints AS kc
          ON i.[object_id] = kc.[parent_object_id]
          AND kc.unique_index_id = i.index_id
        INNER JOIN 
          sys.columns AS c
          ON i.[object_id] = c.[object_id]
          AND ic.column_id = c.column_id
        WHERE
          kc.[type] = 'PK'
          AND kc.parent_object_id = @object_id
        ORDER BY key_ordinal;
    
        SET @sql = LEFT(@sql, LEN(@sql) - 1) + ');';
    
        SELECT COALESCE(@sql, ' ');
    END
    GO
    
  • 至于索引创建脚本,我认为有一种更好的方法可以做到这一点(同样没有显式的游标,不是避免游标是目标,而是代码将更加简洁)。首先,您需要一个函数来从索引生成键或包含列:

    CREATE FUNCTION dbo.BuildIndexColumns
    (
        @object_id        INT,
        @index_id         INT,
        @included_columns BIT
    )
    RETURNS NVARCHAR(MAX)
    AS
    BEGIN
      DECLARE @s NVARCHAR(MAX);
    
      SELECT @s = N'';
    
      SELECT @s = @s + c.name + CASE ic.is_descending_key
        WHEN 1 THEN ' DESC' ELSE '' END + ',' 
        FROM sys.index_columns AS ic
        INNER JOIN sys.columns AS c
        ON ic.[object_id] = c.[object_id]
        AND ic.column_id = c.column_id
        WHERE c.[object_id] = @object_id
        AND ic.[object_id] = @object_id
        AND ic.index_id = @index_id
        AND ic.is_included_column = @included_columns
        ORDER BY ic.key_ordinal;
    
      IF @s > N''
        SET @s = LEFT(@s, LEN(@s)-1);
    
      RETURN (NULLIF(@s, N''));
    END
    GO
    
    有了该函数,ScriptIndexes过程非常简单:

    CREATE PROCEDURE dbo.ScriptIndexesForTable
        @TableName SYSNAME
    AS
    BEGIN
      SET NOCOUNT ON;
    
      DECLARE
          @sql       NVARCHAR(MAX),
          @object_id INT;
    
      SELECT @sql = N'', @object_id = OBJECT_ID(UPPER(@TableName));
    
      SELECT @sql = @sql + 'CREATE '
          + CASE i.is_unique WHEN 1 THEN 'UNIQUE ' ELSE '' END
          + CASE i.[type] WHEN 1 THEN 'CLUSTERED ' ELSE '' END
          + ' INDEX ' + i.name + ' ON ' + QUOTENAME(@TableName) + ' (' 
          + dbo.BuildIndexColumns(@object_id, i.index_id, 0)
          + ')' + COALESCE(' INCLUDE(' 
          + dbo.BuildIndexColumns(@object_id, i.index_id, 1)
          + ')', '') + ';' + CHAR(13) + CHAR(10)
      FROM
          sys.indexes AS i
      WHERE
          i.[object_id] = @object_id
          -- since this will be covered by ScriptPKForTable:
          AND i.is_primary_key = 0
      ORDER BY i.index_id;
    
      SELECT COALESCE(@sql, ' ');
    END
    GO
    

    请注意,我的解决方案并不假定PK是集群的(PK脚本硬代码是集群的,但索引脚本假定任何索引都可以集群)。我也会忽略其他属性,如文件组、分区或筛选索引(2005年无论如何都不支持)。

    哪个过程导致死锁,是编写主键脚本的过程,还是编写索引脚本的过程?为什么要使用信息模式、INDEXPROPERTY等,而不是sys.key约束、sys.index列、sys.index.is集群等?感谢您的评论和脚本!(我很想看看您的索引创建脚本)错误源于脚本过程,而不是创建/更改表的过程-如果您确信调用这些视图不会产生影响,这听起来确实很奇怪。但是,我无法从日志中判断它是在调用索引还是主键存储过程中爆炸。当我构建创建表脚本时,我从以下内容开始:“construct SQL tsql=“USE[”&info.SQLServerDestDatabase&“]”和vbNewLine tsql&=“SET ANSI_NULLS on”&vbNewLine tsql&=“在”&vbNewLine tsql&=“创建表[dbo]。”&info.SQLServerDestTableName&“](&vbNewLine…然后我只需使用:SqlHelper.ExecuteNonQuery(sqlConnString,CommandType.Text,tsql)执行语句即可我能做些什么来防止僵局发展到这一点吗?再一次,我在你的评论中没有看到任何会大喊“僵局!僵局!”您必须更准确地确定它,而不仅仅是猜测脚本的哪一部分导致死锁。在这两种情况下,您的存储过程都只是在构建游标后运行一个SELECT,因此它必须在其他位置(我怀疑在您调用过程后)。首先要做的是修复你的游标…好的-我已经打开了1222跟踪。希望我们能从中获得更多信息。谢谢Aaron。我已经更新了我的答案,包含了一个为给定表生成索引创建脚本的过程(附带一些注意事项,以及用于为键和包含列构建每个列列表的配套函数)。