-
Le visualizzazioni INFORMATION_SCHEMA sono proprio questo:visualizzazioni. Non puoi aggiornarli, quindi è improbabile che causino deadlock. Se vuoi determinare la vera fonte (che presumo abbia qualcosa a che fare con i tuoi alter o altro codice all'interno del cursore che non hai mostrato, o altro codice che stai chiamando in combinazione con queste procedure - poiché seleziona contro visualizzazioni e quindi la selezione delle variabili non può essere la causa), suggerisco di leggere Post del blog di Gail Shaw sull'interpretazione dei deadlock .
-
Nonostante (1) suggerisco ancora di utilizzare viste del catalogo più moderne rispetto a INFORMATION_SCHEMA. Le stesse informazioni possono essere derivate, ad esempio, da sys.key_constraints.
-
Stai usando le opzioni predefinite del cursore; e stai annidando i cursori. Se finisci per usare ancora i cursori, dovresti prendere l'abitudine di usare un cursore che richiede meno risorse (ad es. LOCAL STATIC FORWARD_ONLY READ_ONLY).
-
In realtà non hai bisogno di un cursore per farlo. Ecco come riscriverei lo script della tabella 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
Per quanto riguarda lo script di creazione dell'indice, penso che ci sia un modo migliore per farlo (di nuovo senza cursori espliciti, non che evitare il cursore sia l'obiettivo, ma il codice sarà MOLTO più pulito). Per prima cosa hai bisogno di una funzione per creare una chiave o includere colonne dall'indice:
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
Con quella funzione attiva, una procedura ScriptIndexes è piuttosto semplice:
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
Nota che la mia soluzione non presuppone che il PK sia raggruppato (il tuo script PK codifica CLUSTERED ma lo script dell'indice presuppone che uno qualsiasi degli indici possa essere raggruppato). Ignoro anche proprietà aggiuntive come filegroup, partizionamento o indici filtrati (non supportati comunque nel 2005).