sql >> データベース >  >> RDS >> Sqlserver

INFORMATION_SCHEMA のクエリ時のデッドロック

    <オール> <リ>

    INFORMATION_SCHEMA ビューはまさにそのビューです。それらを更新することはできないため、デッドロックが発生する可能性はほとんどありません。実際のソースを特定したい場合(これは、変更、または表示されなかったカーソル内の他のコード、またはこれらのプロシージャの呼び出しと組み合わせて呼び出している他のコードと関係があると思われます-に対して選択するためビューと変数の選択が原因である可能性はありません)、 デッドロックの解釈に関する Gail Shaw のブログ投稿 .

    <リ>

    (1) にもかかわらず、INFORMATION_SCHEMA よりも最新のカタログ ビューを使用することをお勧めします。たとえば、sys.key_constraints から同じ情報を取得できます。

    <リ>

    デフォルトのカーソル オプションを使用しています。カーソルをネストしています。それでもカーソルを使用する場合は、リソースの消費量が少ないカーソル (LOCAL STATIC FORWARD_ONLY READ_ONLY など) を使用する習慣を身に付ける必要があります。

    <リ>

    これを行うには、実際にはカーソルは必要ありません。 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 スクリプトは CLUSTERED をハードコードしますが、インデックス スクリプトは、いずれかのインデックスがクラスター化される可能性があると想定しています)。また、ファイル グループ、パーティショニング、フィルター処理されたインデックスなどの追加のプロパティも無視します (いずれにしても 2005 ではサポートされていません)。




    1. Oracleで4バイトのUTF8文字を検出する方法

    2. Oracleの「INSERTALL」は重複を無視します

    3. このエラーを修正する方法PHP致命的なエラー:ケーキベイクコンソールで未定義の関数mysql_query()を呼び出す

    4. SQLServerのレコード変更を監査テーブルに記録する