Wie können Sie beim Ausführen eines Skripts mit mehreren Befehlen herausfinden, wo wir uns befinden?

7

Ich habe einige Prozesse, bei denen verschiedene Schritte ausgeführt werden müssen, bevor sie beginnen. Zum Beispiel:

Deaktivieren Sie die Prüfbeschränkung für Fremdschlüssel:

select 'alter table '+fk.table_schema+'.'+fk.table_name
+' NOCHECK CONSTRAINT '+fk.CONSTRAINT_NAME 
from SAProduct.information_schema.table_constraints fk 
join SAProduct.information_schema.tables t
on t.table_schema = fk.table_schema 
and t.table_name = fk.table_name 
WHERE constraint_type='FOREIGN KEY'

Dies wird eine große Liste von Aussagen erzeugen, ich kopiere nur 3:

use saproduct
go
alter table dbo.tblProdClassificationCode NOCHECK CONSTRAINT FK_tblProdClassificationCode_tblProdClassification
alter table dbo.tblProdClassificationCodeDescr NOCHECK CONSTRAINT fk_ProdClassificationCodeDescr_ProdClassificationCode
alter table dbo.tblProdClassificationCodeGenerate NOCHECK CONSTRAINT fk_ProdClassificationCodeGenerate_ProdClassification

Wenn ich das auf einmal ausführen würde, wie würde ich herausfinden, wo ich mich befinde? Mit welchem ​​Tisch habe ich es zu tun und welcher ist der nächste?

Gleiches gilt für das Löschen:

select 'DELETE FROM '+table_schema+'.'+table_name
from saproduct.information_schema.tables 
where table_name like 'tbl%'

Das obige Skript würde die folgenden Aussagen erzeugen:

use saproduct
go
DELETE FROM dbo.tblBLanguage
DELETE FROM dbo.tblBLgCategoryXRef
DELETE FROM dbo.tblBLgSegmentXRef
DELETE FROM dbo.tblProdClassification
DELETE FROM dbo.tblProdClassificationCode
DELETE FROM dbo.tblProdClassificationCodeDescr
DELETE FROM dbo.tblProdClassificationCodeGenerate
DELETE FROM dbo.tblProdClassificationDescr
DELETE FROM dbo.tblProdClassificationMarket
DELETE FROM dbo.tblProdClassificationTier
DELETE FROM dbo.tblProdClassificationValue
DELETE FROM dbo.tblProdData
DELETE FROM dbo.tblProdDataDescr
DELETE FROM dbo.tblProdDataMarket
DELETE FROM dbo.tblProdDataTempTier1Descr
DELETE FROM dbo.tblProdDataTempTier1Tier2Descr
DELETE FROM dbo.tblProdDataTier
DELETE FROM dbo.tblProdDataValue
DELETE FROM dbo.tblProdDataValueDate
DELETE FROM dbo.tblProdDataValueNumber
DELETE FROM dbo.tblProdDataValueString
DELETE FROM dbo.tblProdName
DELETE FROM dbo.tblProdNameSizeAlias
DELETE FROM dbo.tblProdNameSizeRuleAlias
DELETE FROM dbo.tblProdNameStructure
DELETE FROM dbo.tblProdNameStructureDescr
DELETE FROM dbo.tblProduct

Welche Tabelle muss ich als nächstes löschen?

Ich versuche, in einer bestimmten Reihenfolge auf Tabellen zuzugreifen, um Deadlocks zu minimieren, insbesondere wenn ich irgendwelche exklusiven Sperren setzen muss. Es ist nicht hier, aber ich versuche auch, eine Eskalation der Sperren zu vermeiden, damit es komplex wird. Ich mag es zu "sehen", was genau los ist. Ich verwende SQL Server 2014:

Microsoft SQL Server 2014 - 12.0.2000.8 (X64) 
    Feb 20 2014 20:04:26 
    Copyright (c) Microsoft Corporation
    Developer Edition (64-bit) on Windows NT 6.3 <X64> (Build 9600: ) (Hypervisor)
Marcello Miorelli
quelle
Beobachten Sie die Ausführung des Skripts und möchten nur eine regelmäßige Ausgabe?
Aaron Bertrand

Antworten:

12

Ich stimme Aaron zu, dass RAISERROR...WITH NOWAITdies sehr nützlich sein kann und wahrscheinlich der richtige Weg ist, wenn Sie die volle Kontrolle über das Skript haben, das generiert wird.

Wenn derzeit ein langes Skript ausgeführt wird und Sie das Skript nicht ändern können, um RAISERRORAnrufe hinzuzufügen , gibt es auch weniger direkte Möglichkeiten, diese Informationen abzurufen.

Testskript

Hier ist ein Testskript, das Sie ausführen können, um die beiden folgenden Ansätze zu demonstrieren:

SELECT 1
WAITFOR DELAY '00:00:15'
SELECT 2
WAITFOR DELAY '00:00:15'
SELECT 3

sp_whosiasctive

Während Sie dieses Skript ausführen , können Sie mit sp_whoisactive die aktuelle Serveraktivität anzeigen. Sie können häufig den Abfrageplan für die bestimmte Anweisung anzeigen, die gerade ausgeführt wird. In meinem Fall sehe ich Folgendes, da die WAITFORAnweisung höchstwahrscheinlich zu einem bestimmten Zeitpunkt ausgeführt wird:

Geben Sie hier die Bildbeschreibung ein

Verwenden von sys.dm_exec_requests.statement_start_offset

Alternativ hat Conor Cunningham auch einen Beitrag zum Extrahieren der Anweisung aus sys.dm_exec_query_statsAND sys.dm_exec_sql_text. Ich glaube, dies wurde noch sp_whoisactivenicht berücksichtigt, aber Sie können eine Abfrage wie die folgende verwenden, um sowohl die aktuelle ausführende Anweisung als auch den gesamten Stapel anzuzeigen.

Geben Sie hier die Bildbeschreibung ein

SELECT er.session_Id AS spid
    --Use the full batch text and the start/end offset of the currect statement to figure 
    --out the SQL that is currently executing. This logic is based on the blog post above
    --but has been updated in light of strange cases in SQL Server that caused the original
    --blog post logic to crash with out of bounds errors on the SUBSTRING operation.
    , SUBSTRING (qt.text 
                , (CASE WHEN er.statement_start_offset > DATALENGTH(qt.text) 
                    THEN 0 ELSE er.statement_start_offset/2 END)+1
                , (CASE WHEN er.statement_end_offset <= 0 THEN DATALENGTH(qt.text)
                    ELSE er.statement_end_offset 
                    END - CASE WHEN er.statement_start_offset > DATALENGTH(qt.text) 
                        THEN 0 ELSE er.statement_start_offset/2 END)
                    + 1
                ) AS query
    , qt.text AS parent_query
FROM sys.dm_exec_requests er
JOIN sys.dm_exec_sessions s
    ON s.session_id = er.session_id
    AND s.session_id <> @@SPID      -- Ignore this current statement.
    AND s.is_user_process = 1       -- Ignore system spids.
    AND s.program_name NOT LIKE '%SQL Server Profiler%' -- Ignore profiler traces
OUTER APPLY sys.dm_exec_sql_text(er.sql_handle)as qt
ORDER BY spid
Geoff Patterson
quelle
8

Hier ist eine Möglichkeit, ein Skript zu generieren, das nach Abschluss eines Befehls Daten auf dem Bildschirm ausgibt und auch den nächsten ankündigt. Wichtig ist, dass Sie RAISERRORmit verwenden, NOWAITdamit Sie nicht vom Pufferausgabemanager in SSMS abhängig sind und entscheiden, wann die PRINTAusgabe im Nachrichtenbereich angezeigt werden soll .

DECLARE @sql NVARCHAR(MAX) = N'';

SELECT @sql += N'  RAISERROR(''Next is ' 
  + QUOTENAME(s.name) + N'.'
  + QUOTENAME(t.name) + ''',0,1) WITH NOWAIT;
  --DELETE ' + QUOTENAME(s.name) + N'.'
  + QUOTENAME(t.name) + ';
  RAISERROR(''Finished ' 
  + QUOTENAME(s.name) + N'.'
  + QUOTENAME(t.name) + ''',0,1) WITH NOWAIT;'
FROM saproduct.sys.schemas AS s
INNER JOIN saproduct.sys.tables AS t
ON s.[schema_id] = t.[schema_id]
WHERE t.name LIKE N'tbl%';

PRINT @sql;
--EXEC saproduct.sys.sp_executesql @sql;

Dies hat eine Ausgabe wie diese (entfernen Sie die, --wenn Sie es wirklich ausführen möchten):

  RAISERROR('Next is [dbo].[Table1]',0,1) WITH NOWAIT;
  --DELETE [dbo].[Table1];
  RAISERROR('Finished [dbo].[Table1]',0,1) WITH NOWAIT;
  RAISERROR('Next is [dbo].[Table2]',0,1) WITH NOWAIT;
  --DELETE [dbo].[Table2];
  RAISERROR('Finished [dbo].[Table2]',0,1) WITH NOWAIT;
  ...

( Warum ich die proprietären Katalogansichten anstelle der unvollständigen INFORMATION_SCHEMAAnsichten verwende .)

Aaron Bertrand
quelle