Ich schreibe dynamisches SQL, um meine NONCLUSTERED
Indizes zu identifizieren und, wenn ich mich verrückt genug fühle, automatisch in CLUSTERED
Indizes umzuwandeln .
Die Zeile ORDER BY 1,2,3 DESC;
in der folgenden SQL dient dazu, DROP INDEX...
Anweisungen vor ALTER TABLE...
Anweisungen auszugeben, um zuerst den NONCLUSTERED-Index zu TROPFEN und dann einen CLUSTERED-Index hinzuzufügen. Ich musste DESC
die Nachspalte 3 hinzufügen , um zuerst den DROP zu erhalten, gefolgt vom ALTER. Das ist rückwärts, es sei denn, ich verliere es!
DECLARE @Server nvarchar(max);
DECLARE @Database nvarchar(max);
DECLARE @cmd nvarchar(max);
DECLARE @IndexType int;
SET @IndexType = 2; /* 1 is CLUSTERED, 2 is NONCLUSTERED */
SET @Server = 'MyServer';
SET @Database = 'MyDatabase';
SET @cmd = '
DECLARE @cmd nvarchar(max);
SET @cmd = ''
SET NOCOUNT ON;
DECLARE @IndexInfo TABLE (TableName nvarchar(255), IndexName nvarchar(255), IndexColumnName nvarchar(255));
INSERT INTO @IndexInfo (TableName, IndexName, IndexColumnName)
SELECT t.name AS TableName, i.name AS IndexName, c.name AS IndexColumnName /*, t.create_date, ic.*, c.* */
FROM sys.tables t
LEFT JOIN sys.indexes i ON t.object_id = i.object_id
LEFT JOIN sys.index_columns ic ON i.object_id = ic.object_id AND i.index_id = ic.index_id
LEFT JOIN sys.columns c ON i.object_id = c.object_id and ic.column_id = c.column_id
WHERE i.is_primary_key = 1
AND i.type = ' + CAST(@IndexType as nvarchar(max)) + '
ORDER BY t.create_date desc;
DECLARE @t1 nvarchar(max);
DECLARE @t2 nvarchar(max);
DECLARE @t3 nvarchar(max);
DECLARE @cmd nvarchar(max);
DECLARE cur CURSOR FOR
SELECT TableName, IndexName, 1 AS ExecOrder, ''''DROP INDEX '''' + IndexName + '''' ON '''' + TableName + '''';'''' FROM @IndexInfo I
UNION ALL
SELECT TableName, IndexName, 2 AS ExecOrder, ''''ALTER TABLE '''' + TableName + '''' ADD CONSTRAINT PK_'''' + TableName + ''''_'''' + IndexColumnName + '''' PRIMARY KEY CLUSTERED ('''' + IndexColumnName + '''')'''' + '''';'''' FROM @IndexInfo I
ORDER BY 1,2,3 DESC;
OPEN cur;
FETCH NEXT FROM cur INTO @t1, @t2, @t3, @cmd;
WHILE @@FETCH_STATUS = 0
BEGIN
PRINT @cmd;
FETCH NEXT FROM cur INTO @t1, @t2, @t3, @cmd;
END
CLOSE cur;
DEALLOCATE cur;
'';
EXEC ' + @Server + '.' + @Database + '.sys.sp_executesql @cmd;
';
PRINT @cmd;
sql-server
sql-server-2005
dynamic-sql
Max Vernon
quelle
quelle
Antworten:
Die
PRINT
Anweisung in derWHILE
Schleife wird in der erwarteten Reihenfolge ausgeführt, die Ausgabe wird jedoch vor dersys.sp_executesql
Rückgabe gepuffert . Implementierungsdetails bedeuten, dass die gepufferte Ausgabe umgekehrt wird.Wenn Sie
RAISERROR (@cmd, 0, 1) WITH NOWAIT;
anstelle vonPRINT
verwenden, wird der Puffer nach jedem Aufruf geleert, sodass Sie die Ergebnisse in der erwarteten Reihenfolge erhalten. IIRC funktioniert derNOWAIT
Trick nur pro Zeile für die ersten 500 Zeilen. Auf jeden Fall ist dies alles undokumentiertes Zeug, das sich jederzeit ändern kann. Verlassen Sie sich also bitte nicht darauf - ich erwähne es nur, um zu erklären, was Sie sehen.Die Umkehrung erfolgt nicht, wenn Sie den
sp_executesql
Anruf durchEXEC (@cmd) AT ' + @Server + '
einenUSE database
Befehl ersetzen, dem ein Befehl vorangestellt ist,@cmd
und der Verbindungsserver für RPC aktiviert sein muss. Dies ist auch keine Empfehlung, nur die Ausgabeumkehrung zu zeigen, ist eine Eigenart vonsp_executesql
.quelle
Angesichts der neuen Informationen in den Kommentaren gibt es mindestens drei Lösungen dafür, die nach der tatsächlichen Reaktion kein Durcheinander von dynamischem SQL und Handbuch erfordern:
Verwenden Sie ein Lineal
Im Ernst, er ist ein DBA mit Aufgaben in Ihrem Unternehmen. Sicherlich können Sie eine Richtlinie implementieren, bei der Tabellen außer in bestimmten Szenarien Cluster-Indizes haben (und in diesem Fall müssen sie abgemeldet sein). Wenn dies als Richtlinie angegeben wird, wird dies zu einem potenziell quantifizierbaren Maß für die Arbeitsleistung.
Implementieren Sie einen DDL-Trigger
Es ist sehr einfach,
CREATE_TABLE
Ereignisse in DDL-Triggern zu erfassen und dann die Katalogansichten sys.indexes oder sys.partitions auf das Vorhandensein eines Clustered-Index zu überprüfen. Kein Clustered-Index? Rollback. Dadurch wird die Möglichkeit ausgeschlossenSELECT INTO
, da Sie keinen Clustered-Index im Voraus definieren können, aber vielleicht ist das in Ordnung.Lass ihn sich in Azure entwickeln
Sie können keine Tabelle in der Cloud ohne einen Clustered-Index erstellen. Wenn Sie ihn dort entwickeln lassen, sind keine Lineale oder DDL-Trigger erforderlich.
Warum benutzt du Ordnungszahlen ? Anstatt:
Versuchen Sie, die Aliase direkt zu referenzieren:
Außerdem verwenden Sie einen Cursor zum Aufbau
@cmd
und ich würde erwarten, dass Sie ihn irgendwo anhängen. So wie es aussieht, durchlaufen Sie den Cursor, führen jedoch immer nur@cmd
die allerletzte Iteration in der Schleife aus. Was ist der Zweck des Cursors? Und warum verwenden Sie keine besseren Cursoroptionen, wenn der Cursor tatsächlich notwendig ist? (Wenn dies nicht der Fall ist, können Sie es in eine einzelne TOP-Abfrage ändern.)quelle