Wissen

Praxis-Artikel und Buchkapitel zu SQL-Performance, Sicherheit und Hochverfügbarkeit – alle frei verfügbar.

Beratung

Festpreis-Analyse mit Bericht und Handlungsempfehlung – oder strategische Begleitung bei Architektur, Migration und Hochverfügbarkeit.

Fachbücher

Die fünfbändige Reihe „Ulis SQL-Bibliothek“ – Band 1 verfügbar. Leseprobe herunterladen!

Tools

UB.SimSQL: SQL-Server-Lastsimulator mit regelbasierten Konfigurationsempfehlungen. Lokal, ohne Cloud, ohne Abo.

Schulungen

Online-Workshops zu Performance, Sicherheit und Entwicklung – kompakt, hands-on, ohne MOC-Folienschlacht.

Storage Deep Dive: – SQL Server Performance

von

Dieser Artikel ist ein Kapitel aus:
SQL Server Performance & Troubleshooting
Praxisleitfaden, ca. 600 Seiten

[ Hier bei Amazon bestellen ]
[ Mehr zum Buch ]

Storage Deep Dive:

IO-Stack, Latenzen und warum dein RAID-Controller lügt

Warum Storage immer noch der häufigste Performance-Killer ist

Wenn ein SQL Server langsam ist, tippen 80 % aller Admins sofort auf fehlende Indizes oder schlechte Abfragen. Manchmal stimmt das. Oft aber liegt das Problem tiefer — buchstäblich: auf der Festplatte, im SAN, im RAID-Controller. Storage ist die Komponente, die am häufigsten unterschätzt wird, am schlechtesten dokumentiert ist und am meisten Einfluss auf die Gesamtperformance hat.

Ein SQL Server liest und schreibt ständig. Der Buffer Pool hält zwar die "heißen" Seiten im RAM — aber, wenn eine Seite nicht gecacht ist, muss sie von der Platte kommen. Das Transaktionslog wird bei jedem Commit geschrieben, ohne Ausnahme. Backups lesen alles durch. Checkpoints schreiben die schmutzigen Seiten weg. Jede dieser Operationen hat eine Latenz, und diese Latenz summiert sich.

Konkrete Zahlen: Ein typischer OLTP-Server mit 500 Transaktionen pro Sekunde schreibt mindestens 500 Log-IOs pro Sekunde — synchron, denn SQL Server wartet auf die WRITELOG-Bestätigung. Wenn die Log-Latenz von 0,2 ms auf 15 ms steigt, verdreifacht sich die Transaktionsdauer. Der Nutzer bemerkt das. Der Kollege tippt auf "schlechte Nacht". Die Wahrheit liegt auf dem Spinnenplot der Latenzen.

In diesem Kapitel schauen wir uns den gesamten IO-Stack von SQL Server bis zum physischen Medium an, lernen die Latenz-Charakteristika der verschiedenen Medientypen kennen und bauen ein Werkzeugkasten an Diagnose-Werkzeugen auf. Für die tiefere Betrachtung der IO-Wait-Typen verweise ich auf Kapitel 9 (Wait Statistics) — dort werden PAGEIOLATCH_SH, PAGEIOLATCH_EX und WRITELOG im Detail behandelt. Und wer wissen will, was Sparfuchs & Partner aus all diesen Empfehlungen gemacht hat: Kapitel 33 liefert die Antwort.

Der IO-Stack: Von SQL Server bis zum Magnetkopf

Ein IO-Request durchläuft mehrere Software- und Hardware-Schichten, bevor er das Speichermedium erreicht. Jede Schicht kann Latenz addieren — oder sie kaschieren. Das ist der Grund, warum naive Messungen trügen können und warum der RAID-Controller manchmal lügt.

 

Abb. 2.1: Der vollständige IO-Stack: Von SQL Server bis zum physischen Medium

Schicht 1: SQL Server Storage Engine

SQL Server öffnet seine Datenbankdateien mit zwei kritischen Flags: FILE_FLAG_WRITE_THROUGH und FILE_FLAG_NO_BUFFERING. Das erste erzwingt, dass Schreiboperationen nicht im Windows-Cache verweilen — SQL Server will selbst kontrollieren, wann Daten wirklich auf dem Medium sind. Das zweite deaktiviert den Windows Cache Manager komplett: SQL Server verwaltet seinen eigenen Cache (den Buffer Pool), und will keine doppelte Pufferung.

Das Transaktionslog ist eine Sonderrolle: Es wird strikt sequenziell geschrieben. SQL Server schreibt Log-Blöcke und wartet auf WRITELOG-Completion, bevor er den Commit an den Client zurückmeldet. Kein Warten, kein Commit. Das macht das Log zur latenz-kritischsten Datei des gesamten Systems.

 

Definition: Write-Ahead Logging (WAL)

SQL Server schreibt jede Änderung zuerst ins Transaktionslog, bevor die Datenseite im Buffer Pool als "dirty" markiert wird. Das garantiert Durability (das "D" in ACID) — aber kostet synchrone Log-IO. Wer das Log auf langsamen Storage legt, hat automatisch langsame Commits.

 

Schicht 2: Windows I/O Manager und Dateisystem

NTFS ist für SQL Server-Daten fast immer die richtige Wahl — aber es gibt Details, die Performance kosten. Die wichtigste Einstellung: Allocationsunit-Größe. Für SQL Server-Datenbanken sollte sie 64 KB betragen (SQL Server's internes Seitenformat ist 8 KB, aber IO-Operationen laufen typisch in 64-KB-Blöcken). Standard-NTFS formatiert mit 4 KB — jeder IO wird dann in 16 Teiloperationen aufgespalten. Das kostet messbar: auf HDDs zwischen 5 und 20 % Durchsatzverlust.

 

Warnung: NTFS-Allocationsunit nicht vergessen

Falsche Allocationsunit (4 KB statt 64 KB) kostet auf HDDs 5–20% Durchsatz. Auf SSDs und NVMe ist der Effekt kleiner, aber vorhanden. Einmal formatiert: nur durch Umformatieren zu korrigieren. Prüfen mit: fsutil fsinfo ntfsinfo D:\

 

Schicht 3: Treiber und Controller

Der Storage-Controller — ob onboard, PCIe-Karte oder HBA — ist der kritische Vermittler zwischen dem Software-Stack und dem physischen Medium. Er kann enormen Einfluss auf die beobachtete Latenz haben: Ein RAID-Controller mit Write-Back-Cache und Battery Backup Unit (BBU) kann Schreiblatenzen von 15 ms auf unter 0,5 ms drücken — weil er den Write sofort bestätigt und später asynchron auf das Medium schreibt. Das ist die "Lüge" aus dem Kapitel-Titel.

Was passiert, wenn der BBU leer oder defekt ist? Der Controller schaltet automatisch auf Write-Through um — und plötzlich sieht SQL Server die echte Medien-Latenz. Aus 0,5 ms werden 15 ms. Der DBA schaut verwirrt auf seinen Bildschirm. Der Server ist nicht "langsamer geworden" — er war die ganze Zeit langsam, nur wurde das kaschiert.

 

Tipp: BBU-Status überwachen

RAID-Controller-BBU-Status ins Monitoring aufnehmen — nicht nur "Disk alive". Ein degradierter BBU ist der häufigste Grund für plötzliche, unerklärliche Performance-Verschlechterungen. Die meisten Controller-Hersteller bieten WMI-Provider oder Kommandozeilen-Tools (z.B. MegaRAID Storage Manager, HPE Array Diagnostic Utility). Diese Werte sollten in der Baseline aus Kapitel 9 erfasst sein.

 

Latenzen: Was ist normal, was ist ein Problem?

Latenz ist die Zeitspanne zwischen dem Absetzen eines IO-Requests und der Rückkehr des Ergebnisses. Sie ist das wichtigste Maß für Storage-Performance — nicht Durchsatz. 100 MB/s klingt gut. Wenn die durchschnittliche Latenz dabei 80 ms beträgt, ist der Server trotzdem kaputt.

 

Medientyp

Lese-Latenz (typisch)

Schreib-Latenz

Sequenzieller Durchsatz

IOPS (random 4K)

HDD (7.200 rpm)

5–15 ms

5–15 ms

100–200 MB/s

80–150

HDD (15.000 rpm)

3–8 ms

3–8 ms

150–220 MB/s

150–200

SSD (SATA)

0,1–0,5 ms

0,05–0,3 ms

500–560 MB/s

50.000–90.000

SSD (SAS/Enterprise)

0,05–0,2 ms

0,02–0,1 ms

500–2.000 MB/s

100.000–200.000

NVMe (Consumer)

0,03–0,1 ms

0,02–0,08 ms

3.000–7.000 MB/s

200.000–500.000

NVMe (Enterprise)

0,02–0,05 ms

0,01–0,03 ms

6.000–12.000 MB/s

500.000–2.000.000

Storage-Array (All-Flash)

0,1–0,5 ms

0,05–0,2 ms

10–100 GB/s

Millionen (gesamt)

Tabelle 2.1: Latenz- und Durchsatz-Charakteristika verschiedener Speichermedien

 

Diese Zahlen sind Richtwerte für unbelastete Systeme. Unter Last — besonders bei zufälligem IO mit kleinen Blöcken (OLTP-typisch 8 KB) — sehen HDDs deutlich schlechter aus: p99-Latenzen von 50–100 ms sind keine Seltenheit. Das ist der Bereich, in dem Nutzer "langsame Anwendung" melden.

Schwellenwerte für SQL Server

Microsoft definiert in der Dokumentation zu sys.dm_io_virtual_file_stats keine offiziellen Schwellenwerte — aber die Community hat sich auf diese Faustregeln geeinigt:

  • Datendateien (Data): Durchschnittliche Latenz < 20 ms ist akzeptabel. Über 50 ms ist ein Problem. Über 100 ms ist ein Notfall.
  • Transaktionslog: Durchschnittliche Latenz < 5 ms ist gut. 5–20 ms ist grenzwertig. Über 20 ms kostet messbar Transaktionsdurchsatz.
  • TempDB: Gelten die gleichen Grenzwerte wie für Datendateien — aber TempDB ist oft latenz-sensibler, da viele interne Operationen durch TempDB gehen (mehr dazu in Kapitel 13).
  • p95/p99: Durchschnittswerte lügen. Ein Server kann im Schnitt 2 ms haben, aber p99 bei 150 ms. Dann leiden 1% aller Requests — genau die, bei denen der CEO gerade eine Abfrage absetzt.
  •  

    Hintergrund: Warum der Durchschnitt lügt

    Latenzen sind typischerweise nicht normalverteilt, sondern long-tail: Viele Requests sind sehr schnell, wenige Requests sind sehr langsam. Der Durchschnitt wird von den schnellen dominiert. Deshalb: Immer p95 und p99 betrachten. sys.dm_io_virtual_file_stats liefert kumulierte Werte — für Percentilen braucht man Extended Events (Kapitel 8) oder eine Baseline aus Kapitel 9.

     

    RAID-Level: Performance-Charakteristik im Detail

    RAID ist eine der am häufigsten missverstandenen Storage-Technologien. "RAID 5 ist gut, weil Redundanz" hört man oft — und das stimmt für Kapazitätseffizienz. Für schreibintensive Workloads ist RAID 5 eine toxische Beziehung.

     

    Abb. 2.2: RAID-Level im Vergleich: Performance-Charakteristik für SQL Server

    Die RAID-5 Write-Penalty: Vier IOs für einen logischen Write

    RAID 5 speichert Daten mit Paritätsinformation. Bei einem Schreibvorgang muss der Controller:

  • Alten Datenwert lesen (1 IO)
  • Alte Parität lesen (1 IO)
  • Neue Parität berechnen (CPU)
  • Neuen Datenwert schreiben (1 IO)
  • Neue Parität schreiben (1 IO)
  • Das sind vier physische IOs für einen logischen Schreibvorgang — der sogenannte "Read-Modify-Write-Cycle". Bei RAID 6 (doppelte Parität) sind es sogar sechs IOs. Auf Spindeln mit 7.200 rpm und 100 OLTP-Writes pro Sekunde bedeutet das 400 physische IO-Operationen — das übersteigt die IOPS-Kapazität der meisten HDD-Arrays problemlos.

    Mit Write-Back-Cache des Controllers ist dieser Effekt versteckt — bis der Cache voll ist oder der BBU ausfällt. Dann sieht man die echte Charakteristik. Auf SSDs und NVMe ist die Penalty weniger dramatisch, weil der Controller die Berechnung schneller durchführt — aber sie ist weiterhin vorhanden.

     

    Warnung: RAID 5/6 und SQL Server: Ein gefährliches Paar

    RAID 5 und 6 sollten nie für SQL Server-Datenbankdateien oder Transaktionslogs verwendet werden, wenn die Workload schreibintensiv ist. Der klassische Fall: 8 GB RAM, Priority Boost aktiviert, RAID 5 mit 7.200-rpm-Spindeln — und der Kollege fragt warum's langsam ist. RAID 10 ist die einzig vernünftige Wahl für produktive OLTP-Datenbanken.

     

    RAID 10: Warum es die erste Wahl ist

    RAID 10 kombiniert Striping (RAID 0) und Mirroring (RAID 1). Jeder Write wird auf zwei Disks gespiegelt — das sind genau zwei physische IOs. Kein Read-Modify-Write, keine Paritätsberechnung. Die Kapazitätseffizienz ist schlechter (50% nutzbar), aber Performance und Resilienz sind optimal. Für SQL Server gilt: RAID 10 für Datendateien, RAID 10 (oder RAID 1) für das Transaktionslog.

    Mit modernen SSDs und NVMe wird RAID weniger kritisch: Ein einzelner NVMe-Drive hat mehr IOPS als ein ganzes RAID-5-Array mit HDDs. Trotzdem bleibt Redundanz wichtig — und RAID 10 ist auch bei Flash die bevorzugte Wahl, weil der Overhead minimal ist.

    DAS, SAN und NAS: Storage-Architekturen für SQL Server

    SQL Server kann auf drei grundlegenden Storage-Architekturen betrieben werden. Jede hat spezifische Performance-Charakteristika, typische Fallstricke und einen Anwendungsbereich.

     

    Architektur

    Protokoll

    Latenz

    Durchsatz

    Typischer Einsatz

    SQL-Server-tauglich

    DAS (Direct Attached)

    SATA/SAS/NVMe

    Sehr niedrig

    Sehr hoch

    Standalone-Server

    Ja — erste Wahl

    SAN (FC/iSCSI)

    Fibre Channel / iSCSI

    Niedrig–mittel

    Hoch

    Enterprise, Cluster

    Ja — mit Sorgfalt

    NAS (SMB 3.0)

    SMB 3.0

    Mittel

    Mittel–hoch

    Dateiserver, Backup

    Eingeschränkt

    NAS (NFS)

    NFS v4.1

    Mittel

    Mittel

    Linux/VMware

    Nicht empfohlen

    Tabelle 2.2: Storage-Architekturen im Vergleich

     

    SAN: Hohe Leistung, hohe Komplexität

    Storage Area Networks (SAN) ermöglichen es, Storage-Ressourcen zentral zu verwalten und zwischen Servern zu teilen. Das klingt gut — und ist es auch, wenn es richtig konfiguriert ist. Die typischen Fallstricke: Zu viele Hosts teilen dasselbe LUN, Queue-Depth-Einstellungen sind falsch, das Zoning ist suboptimal, oder der HBA-Treiber ist veraltet.

    Fibre Channel bietet die niedrigsten Latenzen (0,1–0,3 ms Netzwerk-Overhead) und die höchste Zuverlässigkeit. iSCSI läuft über Standard-Ethernet und ist günstiger, hat aber höheren Protokoll-Overhead (0,2–1 ms, je nach Implementierung). Für SQL Server ist Fibre Channel bevorzugt, wenn hohe Transaktionsdichte gefragt ist.

    NAS: Nur mit SMB 3.0

    SQL Server unterstützt seit 2012 das Ablegen von Datenbankdateien auf SMB 3.0-Freigaben. Das funktioniert — aber nur, wenn das NAS entsprechend ausgelegt ist (dedizierte 10-GbE-Verbindung, All-Flash-Backend) und der SMB-3.0-Multichannel aktiviert ist. NFS ist für SQL Server unter Windows nicht unterstützt; unter Linux (Kapitel 7) gibt es Einschränkungen.

    SQL Server IO-Muster: Was wann und wie viel

    SQL Server ist kein homogener IO-Produzent. Je nach Operation sieht der IO-Stack sehr unterschiedliche Muster — und das beeinflusst die Wahl des Storage-Layouts erheblich.

     

    Operation

    IO-Muster

    Blockgröße

    Latenz-kritisch?

    Anmerkung

    Datenlesen (OLTP)

    Random Read

    8 KB

    Ja

    Einzelne Seiten, nicht vorhersagbar

    Datenlesen (OLAP/Scan)

    Sequenzieller Read

    512 KB–8 MB

    Weniger

    Read-Ahead Mechanismus

    Transaktionslog schreiben

    Sequenzieller Write

    512 B–60 KB

    Sehr stark

    Synchron! WRITELOG ist kritisch

    Checkpoint (Daten)

    Random Write

    8 KB–64 KB

    Mäßig

    Asynchron, bulk write

    Backup lesen

    Sequenzieller Read

    64–1024 KB

    Weniger

    Liest alle Seiten durch

    Restore schreiben

    Sequenzieller Write

    64–1024 KB

    Weniger

    Parallelisierbar

    TempDB (Sorts/Spills)

    Random Read/Write

    8 KB–64 KB

    Ja

    Vermeidbar durch Tuning (Kap. 13)

    Tabelle 2.3: SQL Server IO-Muster nach Operation

     

    Die wichtigste Erkenntnis: Das Transaktionslog ist sequenziell und latenz-kritisch. Es profitiert nicht von RAID-10-Striping (kein Random-IO), aber es braucht niedrige Latenz. Deshalb: Log auf einem dedizierten LUN oder einer dedizierten NVMe, weg von den Datendateien. Auch, wenn die Datendateien auf dem teuren All-Flash-Array liegen — das Log verdient seinen eigenen Storage.

    Autogrowth: Der stille Performance-Killer

    Autogrowth ist eine SQL-Server-Schutzfunktion: Wenn eine Datenbankdatei voll ist, wächst sie automatisch um einen konfigurierten Betrag. Das klingt harmlos. Es ist es nicht.

    Das Problem: Während Autogrowth ausgeführt wird, ist die betroffene Datei für neue Zuweisungen gesperrt. Bei kleinen Wachstumsschritten (der Default ist 10 % — oder schlimmer: 1 MB bei älteren Installationen) wächst die Datei häufig, und jedes Mal gibt es einen kurzen Stall. Hundert Stalls pro Tag sind kein theoretisches Szenario.

     

    Praxisbeispiel: Sparfuchs & Partner: 847 Autogrowth-Events in 120 Minuten

    Bei der Analyse von BUCHSQL01 (Kapitel 33) fanden wir im SQL Server Error Log 847 Autogrowth-Events in einem Zeitraum von 120 Minuten. Wachstumsschritt: 1 MB. Ohne Instant File Initialization (IFI). Das bedeutet: Alle 8,5 Sekunden eine IO-Blockierung, weil der Server die neue Seite erst nullen musste. Auf einer Spindel mit 312 ms p95-Write-Latenz. Jedes einzelne Autogrowth-Event kostete mehrere Sekunden. Die Symptome: Alle paar Minuten Timeouts in der Anwendung. Ursache: Eine 1-MB-Autogrowth-Einstellung aus dem Jahr 2008, die niemand je geändert hatte.

     

    Richtige Autogrowth-Konfiguration

    Die Lösung ist einfach: Datenbankdateien vorab auf die erwartete Größe vorallokieren (Pre-Allocation) und Autogrowth als Sicherheitsnetz konfigurieren — mit vernünftigen Schrittgrößen:

  • Datendateien: Wachstumsschritt 512 MB–1 GB (je nach Datenbankgröße). Niemals unter 256 MB, niemals prozentual.
  • Transaktionslog: Wachstumsschritt 256–512 MB. Prozentual-Wachstum ist bei großen Logs besonders gefährlich (10% von 100 GB = 10 GB Wachstum auf einmal).
  • Autogrowth-Events im Monitoring erfassen — jedes Event ist ein Signal, dass die Pre-Allocation angepasst werden muss.
  • sys.dm_os_performance_counters: "Log Growths" und "Data File Autogrow Events" als Metriken im Baseline-Dashboard.
  •  

    Hinweis: Prozentales Wachstum ist fast immer falsch

    Der Standard-Autogrowth-Wert von 10 % klingt vernünftig — und ist es für eine 100-MB-Datenbank. Für eine 500-GB-Datenbank bedeutet 10 % ein Wachstum von 50 GB auf einmal. Das dauert (ohne IFI): mehrere Minuten. Immer feste Byte-Werte konfigurieren.

     

    Instant File Initialization: Fünf Minuten Arbeit, spürbare Wirkung

    Wenn SQL Server eine neue Datendatei anlegt oder eine Datei vergrößert, nullt Windows den neuen Speicherbereich aus — Sektor für Sektor. Das ist ein Windows-Sicherheitsmerkmal (kein Lesen von fremden Daten aus dem Speicherplatz des vorherigen Benutzers). Es dauert messbar: Bei einer 10-GB-Datei auf einem HDD kann das mehrere Minuten in Anspruch nehmen.

    Instant File Initialization (IFI) umgeht dieses Nullen für Datendateien (nicht für das Log!): Das SQL Server-Dienstkonto bekommt die Windows-Berechtigung SE_MANAGE_VOLUME_NAME, und danach werden neue Datendateien sofort als "verfügbar" markiert, ohne vorheriges Nullen. Das Ergebnis: Autogrowth dauert Millisekunden statt Minuten. Datenbank-Restores werden deutlich schneller.

    -- IFI-Status prüfen: Ist es aktiv?
    -- Erscheint "Instant File Initialization enabled" in der Output-Spalte,
    -- ist IFI aktiv — der beste Zustand.
    SELECT instant_file_initialization_enabled
    FROM   sys.dm_server_services
    WHERE  servicename LIKE 'SQL Server (%';

     

    -- Alternativ: Im SQL Server Error Log prüfen
    -- Beim Start meldet SQL Server: "Database Instant File Initialization: enabled."
    -- oder: "Database Instant File Initialization: disabled."
    EXEC   xp_readerrorlog 0, 1, 'Instant File Initialization';

    IFI aktivieren: SQL Server Configuration Manager öffnen, Dienst-Account ermitteln. Dann in der lokalen Sicherheitsrichtlinie (secpol.msc) unter "Lokale Richtlinien → Zuweisen von Benutzerrechten" die Berechtigung "Durchführen von Volumewartungsaufgaben" (SE_MANAGE_VOLUME_NAME) hinzufügen. SQL Server-Dienst neu starten. Fertig. Aufwand: fünf Minuten. Wirkung: Jede zukünftige Datei-Allokation und jeder Restore läuft schneller.

     

    Warnung: IFI gilt nicht für das Transaktionslog

    Das Transaktionslog wird immer mit Nullen vorbelegt — auch mit IFI. Das ist absichtlich: Das Log enthält sensible Transaktionsdaten, die nicht aus altem Speicher wiederhergestellt werden dürfen. Log-Vergrößerungen sind deshalb immer langsamer als Datei-Vergrößerungen mit IFI.

     

    VLF-Explosion: Wenn das Transaktionslog zur Falle wird

    Das SQL Server Transaktionslog ist intern in Virtual Log Files (VLFs) unterteilt. SQL Server schreibt sequenziell von einem VLF zum nächsten, dreht sich im Kreis, und verwendet inaktive VLFs wieder, wenn sie durch Log-Backup oder Checkpoint freigegeben wurden. Das ist das normale Verhalten. Das Problem entsteht, wenn zu viele VLFs entstehen.

    VLFs entstehen bei jeder Log-Vergrößerung. Wächst das Log in vielen kleinen Schritten, entstehen viele kleine VLFs. SQL Server muss beim Datenbankstart alle VLFs durchgehen, beim Backup alle aktiven VLFs scannen, und beim Recovery alle relevanten VLFs lesen. Mit 48.312 VLFs — wie bei Sparfuchs & Partner (Kapitel 33) — dauert das Datenbankstart messbar länger und Log-Backups werden ineffizient.

    -- VLF-Anzahl pro Datenbank ermitteln
    -- Alles über 1.000 VLFs sollte man sich anschauen.
    -- Alles über 10.000 ist ein Problem. Über 50.000: Sofortmaßnahmen.
    SELECT
        DB_NAME(database_id) AS Datenbank,
        COUNT(*)             AS VLF_Anzahl,
        SUM(vlf_size_mb)     AS Log_Groesse_MB
    FROM   sys.dm_db_log_info(NULL)   -- NULL = alle Datenbanken
    GROUP BY database_id
    ORDER BY VLF_Anzahl DESC;

     

    -- Detailansicht für eine spezifische Datenbank
    -- vlf_status = 2: aktiv (noch nicht überschreibbar)
    -- vlf_status = 0: inaktiv (kann wiederverwendet werden)
    SELECT
        vlf_begin_offset,
        vlf_size_mb,
        vlf_sequence_number,
        vlf_status,
        vlf_parity
    FROM   sys.dm_db_log_info(DB_ID('Produktion'));

    VLF-Explosion beheben

    Zu viele VLFs lassen sich beheben — aber nur mit etwas Geduld und dem richtigen Vorgehen:

  • Log-Backup ausführen (Simple Recovery: CHECKPOINT, dann DBCC SHRINKFILE auf das Log)
  • Log auf eine moderate Größe schrumpfen (DBCC SHRINKFILE — ja, hier ist Shrink ausnahmsweise legitim)
  • Log mit einer einzigen Vergrößerung auf die Zielgröße bringen (CREATE DATABASE oder ALTER DATABASE mit fester Größe)
  • Danach nie wieder 1-MB-Autogrowth verwenden
  •  

    Hintergrund: Wie viele VLFs sind "normal"?

    Microsoft empfiehlt weniger als 50 VLFs als Richtlinie, was in der Praxis für viele Datenbanken zu niedrig ist. Realistische Grenzwerte: Unter 500 VLFs: kein Problem. 500–2.000: überwachen. 2.000–10.000: shrink und reorg einplanen. Über 10.000: umgehend handeln. Die Anzahl optimaler VLFs hängt von der Log-Größe ab — eine 100-GB-Log-Datei mit 200 VLFs à 500 MB ist ideal.

     

    DiskSpd: Storage tatsächlich messen

    Bevor du Entscheidungen über Storage-Konfiguration triffst, miss die tatsächliche Performance. DiskSpd ist das offizielle Microsoft-Werkzeug für Storage-Benchmarks — kostenlos, präzise, und in der Lage, genau die IO-Muster zu simulieren, die SQL Server produziert.

    # DiskSpd - SQL Server OLTP-Simulation (zufälliger 8-KB-Read)
    # -b8K: Blockgröße 8 KB (SQL Server-Seitengröße)
    # -d60: 60 Sekunden Testlaufzeit
    # -o4: 4 ausstehende IOs pro Thread (Queue Depth)
    # -t4: 4 parallele Threads
    # -r: zufällige IO-Verteilung (OLTP-typisch)
    # -W15: 15 Sekunden Warm-up (werden nicht gemessen)
    # -L: Latenz-Statistiken ausgeben (wichtig!)
    diskspd.exe -b8K -d60 -o4 -t4 -r -W15 -L D:\testfile_10GB.dat

     

    # SQL Server Log-Simulation (sequenzieller Write, 512-KB-Blöcke)
    # -b512K: Log-ähnliche Schreibgröße
    # -w100: 100% Writes
    # -s: sequenziell (nicht zufällig)
    # -L: Latenzen anzeigen — das ist was zählt
    diskspd.exe -b512K -d60 -o4 -t2 -w100 -s -W15 -L L:\testfile_log.dat

     

    # Testdatei anlegen (10 GB)
    # DiskSpd kann das selbst: Einfach Dateipfad angeben,
    # der nicht existiert — DiskSpd legt ihn an.

    Die wichtigsten Kennzahlen in der DiskSpd-Ausgabe: "avg." in der Latenz-Sektion (Durchschnitt), "50th" (Median), "90th", "95th", "99th" (Percentilen) und "99.99th" (worst case). Der Vergleich mit den Grenzwerten aus der Tabelle oben zeigt sofort, ob der Storage die SQL Server-Anforderungen erfüllt.

     

    Tipp: DiskSpd vor der Produktionsinstallation ausführen

    Storage-Tests gehören zur Pre-Deployment-Checkliste: bevor SQL Server installiert wird, DiskSpd auf allen Storage-Pfaden ausführen und die Ergebnisse dokumentieren. Das ist die Baseline. Wenn sechs Monate später Performance-Probleme auftreten, kannst du vergleichen: War der Storage damals schon so langsam, oder hat sich etwas geändert? Ohne Baseline ist Performance-Analyse Rätselraten — wie in Kapitel 9 ausführlich beschrieben.

     

    SQL Server IO-DMVs: Das Latenz-Dashboard

    SQL Server sammelt IO-Statistiken in der Dynamic Management View sys.dm_io_virtual_file_stats. Sie liefert kumulative Werte seit dem letzten Neustart — und damit die Grundlage für eine einfache, aber effektive IO-Latenz-Analyse.

    -- IO-Latenz-Dashboard: Durchschnittliche Lese- und Schreiblatenzen
    -- pro Datenbankdatei seit dem letzten SQL-Server-Start.
    -- Werte in Millisekunden. Alles über 20ms (Data) / 5ms (Log) prüfen.
    SELECT
        DB_NAME(vfs.database_id)         AS Datenbank,
        mf.name                          AS Dateiname,
        mf.physical_name                 AS Pfad,
        mf.type_desc                     AS Dateityp,
        vfs.io_stall_read_ms  / NULLIF(vfs.num_of_reads,  0) AS Lese_Latenz_ms,
        vfs.io_stall_write_ms / NULLIF(vfs.num_of_writes, 0) AS Schreib_Latenz_ms,
        vfs.io_stall          / NULLIF(vfs.num_of_reads + vfs.num_of_writes, 0)
                                         AS Gesamt_Latenz_ms,
        vfs.num_of_reads                 AS Anzahl_Reads,
        vfs.num_of_writes                AS Anzahl_Writes,
        CAST(vfs.num_of_bytes_read  / 1048576.0 AS DECIMAL(18,1)) AS Gelesen_MB,
        CAST(vfs.num_of_bytes_written / 1048576.0 AS DECIMAL(18,1)) AS Geschrieben_MB
    FROM   sys.dm_io_virtual_file_stats(NULL, NULL) AS vfs
    JOIN   sys.master_files                          AS mf
           ON  vfs.database_id = mf.database_id
           AND vfs.file_id     = mf.file_id
    ORDER BY Gesamt_Latenz_ms DESC;

     

    -- Delta-Abfrage: Latenzen über 60 Sekunden messen (genauer als kumulativ)
    -- Erst Snapshot nehmen, 60 Sekunden warten, zweiten Snapshot nehmen,
    -- Differenz berechnen. So bekommst du aktuelle Latenzen statt Lifetime-Werte.

    Diese Abfrage liefert kumulative Durchschnittswerte. Das bedeutet: Wenn der Server vor drei Monaten eine Woche lang langsam war und danach wieder normal lief, sind die kumulativen Werte verzerrt. Für genaue aktuelle Messung: Zwei Snapshots mit 60 Sekunden Abstand nehmen und die Differenz berechnen. Das Prinzip des Delta-Messens wird in Kapitel 9 (Wait Statistics) ausführlich erklärt — es gilt für DMVs generell.

    Diagnose: IO-Performance-Probleme erkennen und einordnen

    Symptome

     

    Hinweis: Symptome eines IO-Performance-Problems

    Folgendes deutet auf IO-Probleme hin: • Nutzer melden sporadisch langsame Abfragen — besonders bei großen Reads oder unter Last • PAGEIOLATCH_SH, PAGEIOLATCH_EX oder WRITELOG dominieren die Wait Statistics (Kapitel 9) • sys.dm_io_virtual_file_stats zeigt Latenzen über 20 ms (Data) oder 5 ms (Log) • SQL Server Error Log enthält Meldungen "SQL Server has encountered X occurrence(s) of I/O requests taking longer than 15 seconds" • Task-Manager oder Performance Monitor zeigen hohe Disk Queue Length (über 2 pro Disk = Problem) • Backup-Laufzeiten nehmen zu ohne Änderung der Datenbankgröße

     

    So misst du das

     

    Hinweis: IO-Performance messen: Drei Ebenen

    Ebene 1 — SQL Server intern (sofort): SELECT … FROM sys.dm_io_virtual_file_stats — Abfrage oben. Gibt durchschnittliche Latenzen seit Neustart. Ebene 2 — Windows Performance Monitor: Counters: "PhysicalDisk\Avg. Disk sec/Read", "PhysicalDisk\Avg. Disk sec/Write", "PhysicalDisk\Current Disk Queue Length". Schwellenwert Queue Length > 2. Ebene 3 — DiskSpd Benchmark: Synthetischer Last-Test mit SQL-Server-typischen IO-Mustern (8 KB random read, 512 KB sequential write). Liefert Percentil-Latenzen — aussagekräftiger als Durchschnitte.

     

    Typische Fehlinterpretationen

     

    Warnung: Fehlinterpretationen bei IO-Diagnose

    1. "Hohe Disk-Aktivität ist schlecht" — Nein. Hohe Disk-Aktivität mit niedrigen Latenzen ist gut. Erst, wenn Latenzen steigen, wird Disk-Aktivität zum Problem. 2. "Backup-IO stört nicht" — Doch. Ein Backup, das mit hohem Durchsatz läuft, konkurriert mit produktivem IO um Queue-Slots. Backup-Window planen oder Backup-Drosselung nutzen. 3. "NVMe ist immer schnell" — Im Durchschnitt ja. Aber p99-Latenzen variieren stark. Günstige Consumer-NVMe-Drives können unter Last dramatisch einbrechen (Thermal Throttling, Cache-Sättigung). 4. "Kumulierte DMV-Werte zeigen die aktuelle Situation" — Nein. Immer Delta-Messungen verwenden für aktuelle Latenzen. Kumulierte Werte sind durch Lastspitzen der Vergangenheit verzerrt.

     

    Erste Gegenmaßnahmen

     

    Tipp: Sofortmaßnahmen bei IO-Problemen

    1. Autogrowth prüfen: Wächst eine Datei gerade? DBCC SQLPERF(LOGSPACE) und Error Log prüfen. 2. Backup läuft gerade? sys.dm_exec_requests nach BACKUP DATABASE oder RESTORE DATABASE filtern. Falls ja: MAXTRANSFERSIZE erhöhen oder Backup in Nebenzeiten verschieben. 3. IO-Last identifizieren: sys.dm_exec_requests JOINen mit sys.dm_io_virtual_file_stats-Deltas — welche Session produziert gerade die meisten IOs? 4. RAID-Controller-Status prüfen: BBU-Status laut Controller-Management-Tool. Write-Through statt Write-Back? 5. Wait Statistics: PAGEIOLATCH-Anteil an allen Waits (Kapitel 9). Über 30%? Storage-Problem fast sicher.

     

    Zusammenfassung

    Storage ist der häufigste Performance-Killer für SQL Server — und gleichzeitig die am häufigsten unterschätzte Komponente. Die wichtigsten Erkenntnisse dieses Kapitels:

  • Der IO-Stack hat mehrere Schichten: SQL Server, Windows, Treiber, Controller, Medium. Jede kann Latenz addieren oder kaschieren.
  • Latenzschwellenwerte: Data unter 20 ms, Log unter 5 ms. Messbar mit sys.dm_io_virtual_file_stats und DiskSpd.
  • RAID 5/6 ist für schreibintensive SQL-Server-Workloads ungeeignet (4 bzw. 6 physische IOs pro Write). RAID 10 ist die richtige Wahl.
  • Autogrowth mit kleinen Schritten tötet die Performance durch häufige IO-Blockierungen. Vorallokieren und vernünftige Schrittgrößen (512 MB+) sind Pflicht.
  • Instant File Initialization: Fünf Minuten Konfigurationsarbeit, sofortiger und dauerhafter Gewinn bei Datei-Allokationen.
  • VLF-Explosion durch häufige kleine Log-Wachstumsschritte verlangsamt Datenbankstart, Recovery und Log-Backups.
  • DiskSpd ist das Werkzeug der Wahl für Storage-Benchmarks vor und während der Produktivphase.
  • NTFS Allocationsunit auf 64 KB setzen für SQL Server-Volumes — Standard 4 KB kostet 5–20 % Durchsatz auf HDDs.
  • Ein funktionierendes Storage-Setup ist die Grundvoraussetzung für alles, was danach kommt. Query-Tuning auf langsamen Platten ist wie Sportwagen-Tuning auf Feldwegen. Die Performance-Gewinne sind real, aber begrenzt.

    Im nächsten Kapitel verlassen wir die physische Hardware und schauen uns an, was passiert, wenn SQL Server in einer virtuellen Maschine läuft. Virtualisierung ist heute Standard — aber sie bringt eine eigene Klasse von Performance-Problemen mit sich, von Memory Ballooning bis vNUMA-Konfigurationsfehler. Alles in Kapitel 3: Virtualisierung.

     

    Kapitel 3