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 ではサポートされていません)。