Ich habe mehrere Datenbanken auf einem Produktionsserver, die Hunderte von Gigabyte groß sind, und es werden täglich viele tausend Transaktionen ausgeführt.
Fast alle diese Datenbanken werden mithilfe der SQL Server-Spiegelung gespiegelt.
Obwohl wir die Größe der physischen Protokolldateien sorgfältig geplant haben, um sie an die erwartete Aktivität der Protokolldateien anzupassen. Gelegentlich geht etwas schief und die Protokolle müssen über unser vorhergesagtes Maximum hinaus wachsen. Wir haben alle Protokolldateien so eingerichtet, dass sie um 8192 MB wachsen. Wenn die Datenbank jedoch unter dem Druck steht, die Protokolldatei zu vergrößern, wird das Protokoll manchmal nur in sehr kleinen Blöcken vergrößert, wodurch in einigen Fällen Hunderttausende von virtuellen Protokolldateien (VLFs) erstellt werden. .
Ich habe verstanden, wie wichtig es ist, die Anzahl der VLFs niedrig zu halten, als eine unserer Produktionsdatenbanken mit über 200.000 VLFs unerwartet wiederhergestellt wurde. Die Wiederherstellung dauerte mehr als 20 Stunden. Während dieser Zeit konnte ein Teil unseres Geschäfts nicht betrieben werden.
Ich benötige eine Lösung, die die Anzahl der virtuellen Protokolldateien für alle auf einem Server vorhandenen Datenbanken überwachen und eine Warn-E-Mail senden kann, wenn eine bestimmte Protokolldatei mehr als eine bestimmte Anzahl von VLFs enthält.
Ich weiß, dass DBCC LOGINFO;
die Liste der VLFs zurückgegeben wird, ich möchte dies jedoch nicht manuell ausführen.
Ich habe die folgende SQL-Anweisung erstellt, die eine schöne Tabelle mit den Datenbanken zusammen mit der Anzahl der VLFs erstellt. Ich weiß jedoch nicht, wie ich dies in einen SQL Agent-Job einfügen kann, um unserem Team eine E-Mail zu senden, wenn eine Datenbank eine "x" -Nummer hat von VLFs.
DECLARE @cmd_per_database_prefix nvarchar(max);
DECLARE @cmd_per_database nvarchar(max);
DECLARE @database_name nvarchar(255);
SET @cmd_per_database = '';
SET @cmd_per_database_prefix =
'
SET NOCOUNT ON;
DECLARE @vlf_count_table TABLE (database_name nvarchar(255), vlf_count int);
DECLARE @params nvarchar(max);
DECLARE @db_name nvarchar(255);
DECLARE @vlf_count int;
SET @params = ''@db_name nvarchar(255) OUTPUT, @vlf_count int OUTPUT'';
DECLARE @cmdGetVLFCount nvarchar(max);
SET @cmdGetVLFCount =
''
DECLARE @tab TABLE
(
FileId int
, FileSize nvarchar(255)
, StartOffset nvarchar(255)
, FSeqNo nvarchar(255)
, Status int
, Parity int
, CreateLSN nvarchar(255)
);
DECLARE @cmd nvarchar(max);
SET @cmd = ''''DBCC LOGINFO;'''';
INSERT INTO @tab
EXEC sp_executesql @cmd;
SET @db_name = db_name();
SET @vlf_count = (select count(*) FROM @tab t);
'';
';
DECLARE cur CURSOR FOR
SELECT NAME
FROM sys.databases
WHERE database_id > 4 and state=0;
OPEN cur;
FETCH NEXT FROM cur INTO @database_name;
WHILE @@FETCH_STATUS = 0
BEGIN
SET @cmd_per_database = @cmd_per_database +
'
EXEC ' + @database_name + '.sys.sp_executesql @cmdGetVLFCount, @params, @db_name OUTPUT, @vlf_count OUTPUT;
INSERT INTO @vlf_count_table (database_name, vlf_count) VALUES (@db_name, @vlf_count);
';
FETCH NEXT FROM cur INTO @database_name;
END
SET @cmd_per_database = @cmd_per_database_prefix + @cmd_per_database + char(13) + char(10) + 'select * from @vlf_count_table t;';
EXEC sp_executesql @cmd_per_database;
CLOSE cur;
DEALLOCATE cur;
Der Versuch, dies mit INSERT...EXEC
in eine Tabelle zum Anhängen an eine E-Mail mit auszugeben, sp_send_dbmail
erweist sich als zwecklos.
SQL Server drosselt mit:
An INSERT EXEC statement cannot be nested.
Msg 8164, Level 16, State 1, Line 5
quelle
Antworten:
Hier ist ein etwas einfacherer Ansatz, der den Cursor und die verschachtelte Ausführung vermeidet:
quelle
@sql
aus einerSELECT
Aussage baut - und dabei das Offensichtliche völlig übersehenSELECT @sql = @sql +
. Manchmal hasse ich meinen Entwickler- / Verfahrenshintergrund! Ich denke immer, es ist besser zu verwenden,SET @sql = @sql +
währendSELECT @sql =
Typkonstrukte mich aus irgendeinem seltsamen Grund erschaudern lassen. Nicht mehr so !!!O'Brien
. Sie können das beheben, aber es ist hässlich - einfacher, Datenbanken keine schlecht ausgewählten Namen zu geben. :-)Sie können eine temporäre Tabelle erstellen und in der dynamischen SQL verwenden. Ich habe mich nicht an Ihrem Code orientiert, aber dies zeigt das Konzept:
quelle
sp_msforeachdb
- siehe hier und hier .