-
INFORMATION_SCHEMA-Ansichten sind genau das – Ansichten. Sie können sie nicht aktualisieren, daher ist es unwahrscheinlich, dass sie Deadlocks verursachen. Wenn Sie die tatsächliche Quelle ermitteln möchten (was vermutlich etwas mit Ihren Änderungen oder anderem Code innerhalb des Cursors zu tun hat, den Sie nicht angezeigt haben, oder anderem Code, den Sie in Kombination mit dem Aufrufen dieser Prozeduren aufrufen - da wählt gegen Views und das anschließende Auswählen von Variablen kann nicht die Ursache sein), schlage ich vor, Gail Shaws Blogbeitrag zur Interpretation von Deadlocks .
-
Trotz (1) schlage ich immer noch vor, modernere Katalogansichten als INFORMATION_SCHEMA zu verwenden. Die gleichen Informationen können beispielsweise von sys.key_constraints.
abgeleitet werden -
Sie verwenden die Standard-Cursor-Optionen; und Sie verschachteln Cursor. Wenn Sie immer noch Cursor verwenden, sollten Sie sich angewöhnen, einen weniger ressourcenintensiven Cursor zu verwenden (z. B. LOCAL STATIC FORWARD_ONLY READ_ONLY).
-
Dafür brauchen Sie eigentlich keinen Cursor. So würde ich das PK-Tabellenskript umschreiben:
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
Was das Indexerstellungsskript angeht, denke ich, dass es einen besseren Weg gibt, dies zu tun (wieder ohne explizite Cursor, nicht dass das Vermeiden des Cursors das Ziel ist, aber der Code wird VIEL sauberer sein). Zuerst benötigen Sie eine Funktion, um entweder Schlüssel zu erstellen oder Spalten aus dem Index einzuschließen:
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
Mit dieser Funktion ist eine ScriptIndexes-Prozedur ziemlich einfach:
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
Beachten Sie, dass meine Lösung nicht davon ausgeht, dass der PK geclustert ist (Ihr PK-Skript ist hartcodiert CLUSTERED, aber dann geht Ihr Indexskript davon aus, dass jeder der Indizes geclustert werden könnte). Ich ignoriere auch zusätzliche Eigenschaften wie Dateigruppe, Partitionierung oder gefilterte Indizes (wird 2005 ohnehin nicht unterstützt).