Kapitel 4: Datenbankoptimierung
Sollte es im laufenden Betrieb zu Leistungsproblemen kommen, können Sie die Datenbank über die Schaltfläche „Datenbank optimieren“ unter der Maske “Wartung” automatisch optimieren.
Externe Optimierung
Darüber hinaus können die folgenden bat-Scripte verwendet werden, um die Perofrmance der Datenbank zu verbessern:
Update der Tabellen-Statistiken
Der SQL Server verwendet Statistiken über die Verteilung von Daten in den Tabellen, um zu entscheiden, wie er Abfragen am schnellsten verarbeitet (welche Indizes genutzt werden, wie Tabellen verknüpft werden usw.).
Wenn viele Daten hinzugefügt, geändert oder gelöscht werden, veralten diese Statistiken. Ohne Aktualisierung wählt der Datenbank-Server falsche Ausführungspläne, was das Gesamtsystem enorm verlangsamen kann.
Wann das sinnvoll ist:
Regelmäßige Wartung (z. B. wöchentlich/nächtlich): Außerhalb der Arbeitszeiten per Windows-Aufgabenplanung (Task Scheduler), um die Performance stabil zu halten.
Nach großen Datenimporten/Löschaktionen: Wenn auf einen Schlag Tausende Datensätze hinzugefügt oder geändert wurden.
Bei Performance-Problemen: Wenn die Anwendung plötzlich ungewöhnlich langsam reagiert, obwohl die Serverauslastung normal wirkt.
Dies können sie mit dem folgenden bat-Script automatisieren:
@ECHO OFF
:: ============================================================
:: update-statistics.bat -S <Server> [-E | -U <User> -P <Pass>]
:: ============================================================
SETLOCAL
SET SERVER=%~2
IF "%SERVER%"=="" (
ECHO Verwendung: %~nx0 -S ^<Server^> [-E ^| -U ^<User^> -P ^<Pass^>]
EXIT /B 1
)
:: Auth-Parameter = alles nach -S <Server>
SET AUTH=%3 %4 %5 %6 %7
IF "%AUTH: =%"=="" SET AUTH=-E
SET LOG=%~dp0update-statistics_%DATE:/=-%.log
ECHO [%DATE% %TIME%] Start: %SERVER% >> "%LOG%"
sqlcmd -S "%SERVER%" %AUTH% -d "VISTRAX_3_6_MANDATOR_1" -b ^
-Q "EXEC sp_MSforeachtable 'UPDATE STATISTICS ? WITH FULLSCAN';" >> "%LOG%" 2>&1
IF %ERRORLEVEL% NEQ 0 ECHO [FEHLER] VISTRAX_3_6_MANDATOR_1 & GOTO :END
sqlcmd -S "%SERVER%" %AUTH% -d "VISTRAX_3_6" -b ^
-Q "EXEC sp_MSforeachtable 'UPDATE STATISTICS ? WITH FULLSCAN';" >> "%LOG%" 2>&1
IF %ERRORLEVEL% NEQ 0 ECHO [FEHLER] VISTRAX_3_6 & GOTO :END
ECHO [%DATE% %TIME%] Erfolgreich abgeschlossen. >> "%LOG%"
ECHO Erfolgreich. Log: %LOG%
:END
ENDLOCAL
EXIT /B %ERRORLEVEL%
Performance-Überwachungs-Tool Query Store aktivieren
Der Query Store (Abfragespeicher) ist eine eingebaute Funktion von Microsoft SQL Server, die wie ein “Flugschreiber” für Datenbanken funktioniert. Er zeichnet automatisch auf, welche SQL-Abfragen ausgeführt werden, wie lange sie dauern und welche Ressourcen sie verbrauchen.
Wann das sinnvoll ist:
Performance-Analyse: Wenn Datenbankabfragen langsam laufen und du herausfinden willst, welche Abfragen die meisten Ressourcen (CPU, RAM, I/O) verbrauchen.
Fehlersuche bei Updates: Um Performance-Einbrüche (“Parameter Sniffing” oder schlechte Ausführungspläne) nach Software-Updates oder Datenbank-Migrationen zu erkennen und alte Ausführungspläne zu erzwingen.
sie können dies über das folgende .bat.Script aktivieren:
@ECHO OFF
:: ============================================================
:: enable-querystore-with-cleanup.bat -S <Server> [-E | -U <User> -P <Pass>]
:: ============================================================
SETLOCAL
SET SERVER=%~2
IF "%SERVER%"=="" (
ECHO Verwendung: %~nx0 -S ^<Server^> [-E ^| -U ^<User^> -P ^<Pass^>]
EXIT /B 1
)
SET AUTH=%3 %4 %5 %6 %7
IF "%AUTH: =%"=="" SET AUTH=-E
SET SQL=^
ALTER DATABASE VISTRAX_3_6 SET QUERY_STORE = ON;^
ALTER DATABASE VISTRAX_3_6 SET QUERY_STORE (OPERATION_MODE = READ_WRITE, MAX_STORAGE_SIZE_MB = 100, CLEANUP_POLICY = (STALE_QUERY_THRESHOLD_DAYS = 30));^
ALTER DATABASE VISTRAX_3_6_MANDATOR_1 SET QUERY_STORE = ON;^
ALTER DATABASE VISTRAX_3_6_MANDATOR_1 SET QUERY_STORE (OPERATION_MODE = READ_WRITE, MAX_STORAGE_SIZE_MB = 100, CLEANUP_POLICY = (STALE_QUERY_THRESHOLD_DAYS = 30));
sqlcmd -S "%SERVER%" %AUTH% -b -Q "%SQL%"
IF %ERRORLEVEL% EQU 0 (
ECHO Query Store erfolgreich aktiviert.
) ELSE (
ECHO [FEHLER] Query Store konnte nicht aktiviert werden.
)
ENDLOCAL
EXIT /B %ERRORLEVEL%
Defragmentierung der Datenbank
Zunächst muss die folgende SQL Query ausgeführt werden:
-------------------------------------------------------------------------------
-- Dieser Query stellt die Fragementierung der Indices in beiden Tabellen fest
-- und defragmentiert diese bei Bedarf.
-------------------------------------------------------------------------------
-- Fragmentierung Aktion Grund
-- 10–30% REORGANIZE Online, keine Sperrung, leicht
-- > 30% REBUILD Vollständige Neustrukturierung
-- < 10% (übersprungen) Kein Handlungsbedarf
-------------------------------------------------------------------------------
-- ============================================
-- Alle Indizes defragmentieren – VISTRAX_3_6
-- ============================================
USE VISTRAX_3_6;
GO
DECLARE @TableName NVARCHAR(256);
DECLARE @IndexName NVARCHAR(128);
DECLARE @Fragmentation DECIMAL(5,2);
DECLARE @SQL NVARCHAR(512);
DECLARE frag_cursor CURSOR FOR
SELECT
OBJECT_SCHEMA_NAME(ips.object_id) + '.' + OBJECT_NAME(ips.object_id),
i.name,
ips.avg_fragmentation_in_percent
FROM sys.dm_db_index_physical_stats(DB_ID(), NULL, NULL, NULL, 'LIMITED') ips
JOIN sys.indexes i
ON ips.object_id = i.object_id AND ips.index_id = i.index_id
WHERE ips.index_id > 0 -- Keine Heaps
AND ips.page_count >= 10 -- Nur relevante Indizes
AND ips.avg_fragmentation_in_percent >= 10.0
ORDER BY ips.avg_fragmentation_in_percent DESC;
OPEN frag_cursor;
FETCH NEXT FROM frag_cursor INTO @TableName, @IndexName, @Fragmentation;
WHILE @@FETCH_STATUS = 0
BEGIN
IF @Fragmentation >= 30.0
BEGIN
SET @SQL = 'ALTER INDEX [' + @IndexName + '] ON ' + @TableName + ' REBUILD;';
PRINT 'REBUILD (' + CAST(@Fragmentation AS VARCHAR(5)) + '%) -> ' + @TableName + '.' + @IndexName;
END
ELSE
BEGIN
SET @SQL = 'ALTER INDEX [' + @IndexName + '] ON ' + @TableName + ' REORGANIZE;';
PRINT 'REORGANIZE (' + CAST(@Fragmentation AS VARCHAR(5)) + '%) ->' + @TableName + '.' + @IndexName;
END
EXEC sp_executesql @SQL;
FETCH NEXT FROM frag_cursor INTO @TableName, @IndexName, @Fragmentation;
END;
CLOSE frag_cursor;
DEALLOCATE frag_cursor;
PRINT 'VISTRAX_3_6 – Defragmentierung abgeschlossen.';
GO
-- ===================================================
-- Alle Indizes defragmentieren – VISTRAX_3_6_MANDATOR_1
-- ===================================================
USE VISTRAX_3_6_MANDATOR_1;
GO
DECLARE @TableName NVARCHAR(256);
DECLARE @IndexName NVARCHAR(128);
DECLARE @Fragmentation DECIMAL(5,2);
DECLARE @SQL NVARCHAR(512);
DECLARE frag_cursor CURSOR FOR
SELECT
OBJECT_SCHEMA_NAME(ips.object_id) + '.' + OBJECT_NAME(ips.object_id),
i.name,
ips.avg_fragmentation_in_percent
FROM sys.dm_db_index_physical_stats(DB_ID(), NULL, NULL, NULL, 'LIMITED') ips
JOIN sys.indexes i
ON ips.object_id = i.object_id AND ips.index_id = i.index_id
WHERE ips.index_id > 0
AND ips.page_count >= 10
AND ips.avg_fragmentation_in_percent >= 10.0
ORDER BY ips.avg_fragmentation_in_percent DESC;
OPEN frag_cursor;
FETCH NEXT FROM frag_cursor INTO @TableName, @IndexName, @Fragmentation;
WHILE @@FETCH_STATUS = 0
BEGIN
IF @Fragmentation >= 30.0
BEGIN
SET @SQL = 'ALTER INDEX [' + @IndexName + '] ON ' + @TableName + ' REBUILD;';
PRINT 'REBUILD (' + CAST(@Fragmentation AS VARCHAR(5)) + '%) -> ' + @TableName + '.' + @IndexName;
END
ELSE
BEGIN
SET @SQL = 'ALTER INDEX [' + @IndexName + '] ON ' + @TableName + ' REORGANIZE;';
PRINT 'REORGANIZE (' + CAST(@Fragmentation AS VARCHAR(5)) + '%) -> ' + @TableName + '.' + @IndexName;
END
EXEC sp_executesql @SQL;
FETCH NEXT FROM frag_cursor INTO @TableName, @IndexName, @Fragmentation;
END;
CLOSE frag_cursor;
DEALLOCATE frag_cursor;
PRINT 'VISTRAX_3_6_MANDATOR_1 – Defragmentierung abgeschlossen.';
GO
Anschließend kann das zugehörie Bat Script verwendet werden, um die Fragmeniterung der Bat Script um Fragementierung zu prüfen und ggf. zu defragmentieren:
@ECHO OFF
:: ============================================================
:: defrag-indices-on-necessity.bat -S <Server> [-E | -U <User> -P <Pass>]
:: ============================================================
SETLOCAL
SET SERVER=%~2
IF "%SERVER%"=="" (
ECHO Verwendung: %~nx0 -S ^<Server^> [-E ^| -U ^<User^> -P ^<Pass^>]
EXIT /B 1
)
SET AUTH=%3 %4 %5 %6 %7
IF "%AUTH: =%"=="" SET AUTH=-E
SET SQLFILE=%~dp0check-and-defrag-Indices-both-databases.sql
IF NOT EXIST "%SQLFILE%" (
ECHO [FEHLER] SQL-Datei nicht gefunden: %SQLFILE%
EXIT /B 1
)
sqlcmd -S "%SERVER%" %AUTH% -b -i "%SQLFILE%"
IF %ERRORLEVEL% EQU 0 (
ECHO Index-Defragmentierung erfolgreich abgeschlossen.
) ELSE (
ECHO [FEHLER] Defragmentierung fehlgeschlagen.
)
ENDLOCAL
EXIT /B %ERRORLEVEL%