Positionierung
Performance-Probleme in SQL-Server-Umgebungen sind selten zufällig. Sie entstehen, wenn Abfragen ohne Blick auf Ausführungspläne geschrieben werden, wenn Indizes fehlen oder veraltet sind, wenn Statistiken nicht mehr zur Datenlage passen oder wenn Tabellen wachsen, ohne dass die Datenbankarchitektur darauf ausgelegt ist. Das Ergebnis sind schleichend steigende Laufzeiten, Timeouts in Anwendungen und irgendwann ein System, das unter Last zusammenbricht. Der Schmerz ist real, die Ursache aber fast immer analysierbar und behebbar.
Genau hier liegt mein Schwerpunkt: Ich analysiere SQL-Server-Systeme von innen heraus, mit den Bordmitteln, die SQL Server selbst bereitstellt. Dynamic Management Views, Ausführungspläne, Wait Statistics und der Query Store liefern präzise Diagnosen, ohne dass teure Zusatzwerkzeuge nötig sind. Diese Diagnose führt dann zu konkreten Maßnahmen: ein fehlender Index, eine umformulierte Abfrage, eine Statistikaktualisierung, ein Plan-Guide gegen Parameter-Sniffing oder eine Partitionierung, die einen jahrelang wachsenden Bestand handhabbar macht.
Mein Hintergrund reicht bis 1994 zurück, und ich habe Performance-Probleme in sehr unterschiedlichen Kontexten gelöst: in Transaktionssystemen mit hohem OLTP-Aufkommen, in Data Warehouses mit großen Batch-Ladevorgängen, in SSIS-Strecken mit suboptimalem Datenfluss und in Reporting-Systemen, die unter Last inakzeptabel langsam wurden. MCSA SQL Server 2012 (MOC 70-461/462/463) und Projekterfahrung über alle SQL-Server-Versionen von 2000 bis 2025 sind dabei keine Zertifikatsnummern, sondern die Grundlage dafür, dass ich weiß, wie sich das Verhalten des Servers über Versionen verändert hat und welche Optimierungshebel in welchem Kontext wirken.
Auftraggeber holen mich, wenn ein System zu langsam geworden ist und niemand im Team weiß warum, wenn ein Release bevorsteht und kritische Abfragen noch nicht akzeptable Laufzeiten haben, oder wenn eine nachhaltige Performance-Strategie fehlt, die über das Ad-hoc-Setzen von Indizes hinausgeht. In all diesen Fällen geht es nicht um kosmetische Korrekturen, sondern um eine fundierte Diagnose und Maßnahmen, die dauerhaft wirken.
Was Performance-Tuning umfasst
SQL Server Performance Tuning ist kein einzelner Handgriff, sondern ein Bündel von Disziplinen, die ineinandergreifen. Wer nur Indizes setzt, ohne die Abfrageformulierung zu prüfen, löst vielleicht ein Symptom, nicht die Ursache. Wer Statistiken pflegt, aber Wait Statistics ignoriert, übersieht möglicherweise einen I/O-Engpass, der alle Bemühungen zunichtemacht. Ein vollständiges Tuning-Bild umfasst mehrere Ebenen.
Abfrageebene
Die Abfrageebene ist der häufigste Ansatzpunkt. Hier entscheidet sich, welchen Plan der Optimizer wählt, ob Indizes genutzt werden können und wie viele Zeilen tatsächlich gelesen werden. Schlechte Abfrageformulierungen – implizite Konvertierungen, nicht-sargable Prädikate, übermäßige SELECT-*-Nutzung oder fehlende JOINs – können selbst einen perfekt indizierten Bestand ausbremsen. Das Lesen von Ausführungsplänen ist die zentrale Fertigkeit, um diese Probleme zu sehen.
Index-Ebene
Indizes sind das wirksamste Werkzeug für schnelle Leseoperationen, aber kein Allheilmittel. Zu viele Indizes bremsen Schreiboperationen und vergrößern den Speicherbedarf. Fehlende Indizes erzwingen Table Scans. Die Kunst liegt in der richtigen Balance: Welche Abfragen sind leseintensiv und häufig genug, um einen Index zu rechtfertigen? Welche Spalten sollten als INCLUDE hinzugefügt werden, damit der Index einen Lookup verhindert? Wo lohnt ein gefilterter Index, der nur einen Teil des Bestands abdeckt?
Statistik- und Plan-Ebene
SQL Servers Query Optimizer trifft seine Entscheidungen auf Basis von Statistiken. Veraltete oder irreführende Statistiken führen zu falschen Kardinalitätsschätzungen und damit zu suboptimalen Plänen. Parameter-Sniffing – ein Mechanismus, bei dem SQL Server einen Plan für den ersten Parameter-Wert kompiliert und danach für alle weiteren Werte beibehält – ist eine häufige Ursache für sporadische Performance-Einbrüche, die schwer zu reproduzieren sind. Hier helfen regelmäßige Statistikaktualisierungen, OPTION (RECOMPILE) und der Query Store.
Architektur- und Betriebsebene
Manche Performance-Probleme lassen sich auf Abfrage- oder Indexebene nicht vollständig lösen, weil sie struktureller Natur sind. Tabellen mit hunderten Millionen Zeilen ohne Partitionierung, Batch-Prozesse, die transaktionale Tabellen sperren, fehlende Ladefenster oder unkontrolliertes Wachstum von TempDB sind Beispiele dafür. Auf dieser Ebene kommen Partitionierung, Columnstore-Indizes, TempDB-Konfiguration und Architekturüberlegungen ins Spiel.
- Abfrageformulierung und Ausführungsplan-Analyse
- Index-Strategie: Covering-, Filtered- und Columnstore-Indizes
- Statistikpflege und Umgang mit Parameter-Sniffing
- Tabellen-Partitionierung für wachsende Datenbestände
- Wait Statistics als systemweite Engpassanalyse
- TempDB-Konfiguration und Ressourcensteuerung
- SSIS-Datenfluss-Optimierung und Parallelisierung
- Query Store als historisches Performance-Monitoring
Systematischer Tuning-Workflow
Ein strukturiertes Vorgehen beim Performance-Tuning verhindert, dass man in die häufigste Falle tappt: das Optimieren ohne vorherige Diagnose. Ich folge einem mehrstufigen Workflow, der von der Messung über die Analyse bis zur Umsetzung und Verifikation führt. Jede Maßnahme wird vorher begründet und nachher gemessen.
Der Tuning-Workflow beginnt mit der Messung von Baseline-Metriken, führt über die Engpassanalyse mit DMVs und Ausführungsplänen zur gezielten Maßnahme und schließt mit der Verifikation, ob die Verbesserung tatsächlich eingetreten ist.
Der erste Schritt ist immer die Baseline-Messung. Ohne eine Ausgangsmessung lässt sich nicht beurteilen, ob eine Maßnahme gewirkt hat. Dazu nutze ich SET STATISTICS IO ON und SET STATISTICS TIME ON für einzelne Abfragen sowie sys.dm_exec_query_stats für systemweite Aussagen darüber, welche Abfragen den größten Anteil an CPU-Zeit, logischen Lesezugriffen oder Gesamtlaufzeit haben. Diese Priorisierung ist entscheidend: Nicht jede langsame Abfrage ist ein lohnendes Optimierungsziel – es kommt auf die Kombination aus Laufzeit und Ausführungshäufigkeit an.
Analyse mit Dynamic Management Views
Dynamic Management Views sind das Diagnoseinstrument der ersten Wahl. sys.dm_exec_query_stats liefert kumulierte Laufzeitstatistiken für alle Abfragen im Cache. sys.dm_exec_requests zeigt aktuell laufende Abfragen einschließlich Wartetyp und Wartedauer. sys.dm_os_wait_stats aggregiert Wartestatistiken auf Systemebene und identifiziert, ob der Engpass bei I/O, Speicher, Locking oder CPU liegt. Diese drei DMVs zusammen geben in wenigen Minuten ein klares Bild der Systemlage.
Maßnahme und Verifikation
Erst nach der Diagnose folgt die Maßnahme. Das kann ein neuer Index sein, eine umformulierte Abfrage, eine Statistikaktualisierung, ein Plan-Guide oder – bei strukturellen Problemen – eine Architekturänderung wie Partitionierung oder ein Columnstore-Index. Nach der Umsetzung wird gemessen, ob die erwartete Verbesserung eingetreten ist, und das Ergebnis dokumentiert. Dieser Verifikationsschritt ist nicht optional: Er liefert den Nachweis, dass die Maßnahme wirkt, und schützt davor, Regressionen in anderen Abfragen zu übersehen.
-- 1) Baseline fuer eine einzelne Abfrage messen
SET STATISTICS IO ON;
SET STATISTICS TIME ON;
GO
-- Abfrage mit schlechtem Plan (kein Index auf OrderDate, implizite Konvertierung)
SELECT o.OrderID, o.CustomerID, o.TotalAmount
FROM dbo.Orders AS o
WHERE CONVERT(varchar, o.OrderDate, 104) = '01.06.2025'; -- verhindert Index-Nutzung!
GO
SET STATISTICS IO OFF;
SET STATISTICS TIME OFF;
GO
-- 2) Top-10-Abfragen nach logischen Lesezugriffen systemweit
SELECT TOP 10
qs.total_logical_reads / qs.execution_count AS avg_logical_reads,
qs.execution_count,
qs.total_elapsed_time / qs.execution_count / 1000 AS avg_ms,
SUBSTRING(qt.text, (qs.statement_start_offset/2)+1,
((CASE qs.statement_end_offset
WHEN -1 THEN DATALENGTH(qt.text)
ELSE qs.statement_end_offset
END - qs.statement_start_offset)/2)+1) AS query_text,
qp.query_plan
FROM sys.dm_exec_query_stats AS qs
CROSS APPLY sys.dm_exec_sql_text(qs.sql_handle) AS qt
CROSS APPLY sys.dm_exec_query_plan(qs.plan_handle) AS qp
ORDER BY avg_logical_reads DESC;CONVERT um OrderDate verhindert die Index-Nutzung (nicht sargable). Die DMV-Abfrage priorisiert Optimierungsziele anhand durchschnittlicher logischer Lesezugriffe – aussagekräftiger als reine Gesamtlaufzeit, weil seltene lange Abfragen sonst überbewertet werden.
Wie SQL Server eine Abfrage verarbeitet
Um Performance-Probleme gezielt zu beheben, hilft es zu verstehen, was SQL Server intern tut, wenn eine Abfrage eintrifft. Dieser Lebenszyklus bestimmt, wo Optimierungspotenzial liegt und warum manche Maßnahmen wirken, andere aber nicht.
Der Abfragelebenszyklus zeigt, wie SQL Server eine Abfrage parst, den Plan im Cache sucht, den Optimizer aufruft, den Plan kompiliert und speichert, und schließlich den Execution Engine ausführt – mit Rückgriff auf Buffer Pool und Storage I/O.
Wenn eine Abfrage eintrifft, prüft SQL Server zunächst, ob ein passender Plan bereits im Plan Cache liegt (Trivial Plan Cache / Full Plan Cache Lookup). Findet er einen, wird dieser wiederverwendet – der Optimizer muss nicht erneut rechnen. Dieses Wiederverwendungsprinzip ist effizient, birgt aber die Gefahr des Parameter-Sniffing: Der erste Plan, der für einen bestimmten Parameter-Wert erstellt wurde, ist möglicherweise für andere Werte suboptimal.
Parsing und Algebrisierung
SQL Server zerlegt die Abfrage zunächst syntaktisch (Parsing) und wandelt sie dann in einen logischen Operatorbaum um (Algebrisierung). In diesem Schritt werden auch Name-Auflösung und implizite Konvertierungen vorgenommen. Implizite Konvertierungen – etwa wenn ein varchar-Prädikat auf eine int-Spalte trifft – können dazu führen, dass SQL Server einen vorhandenen Index nicht nutzen kann, weil ein Scan des gesamten Bestands und eine zeilenweise Konvertierung günstiger erscheinen als ein Index-Seek mit Konvertierung.
Query Optimizer und Kardinalitätsschätzung
Der Query Optimizer ist kostenbasiert: Er bewertet verschiedene Ausführungsalternativen anhand von Schätzkosten und wählt den Plan mit den geringsten geschätzten Kosten. Die Grundlage dieser Schätzung sind Statistiken – Histogramme über die Werteverteilung in Spalten. Sind die Statistiken veraltet oder fehlen sie, schätzt der Optimizer falsch, und ein eigentlich guter Plan wird nicht gewählt. Der Optimizer kann zudem nicht alle Möglichkeiten durchprobieren; er hört nach einem internen Timeout auf und nimmt den besten bis dahin gefundenen Plan – bei sehr komplexen Abfragen ein wichtiger Hinweis, warum Vereinfachung helfen kann.
Execution Engine und Buffer Pool
Der eigentliche Zugriff auf Daten läuft über den Buffer Pool. SQL Server liest Seiten möglichst aus dem Arbeitsspeicher (logische Lesezugriffe) und geht nur dann auf den Datenträger (physische Lesezugriffe), wenn eine Seite nicht gecacht ist. Die Kennzahl logical reads in SET STATISTICS IO zeigt deshalb, wie viele Seiten eine Abfrage im Buffer Pool benötigt – unabhängig davon, ob sie physisch gelesen werden mussten. Ein hoher Wert signalisiert, dass entweder sehr viele Daten gelesen werden oder dass ein Scan statt eines Seeks stattfindet.
- Plan Cache: Wiederverwendung spart Compile-Zeit, birgt aber Parameter-Sniffing-Risiken
- Implizite Konvertierungen verhindern Index-Seeks und müssen im Code vermieden werden
- Kardinalitätsschätzung hängt an aktuellen Statistiken – veraltete Statistiken = schlechte Pläne
- Logical Reads messen Buffer-Pool-Zugriffe und sind die wichtigste I/O-Kennzahl je Abfrage
- Query Store ermöglicht historische Planverläufe und erzwungene Plan-Stabilisierung
Ausführungspläne lesen und verstehen
Der Ausführungsplan ist das präziseste Diagnoseinstrument für eine einzelne Abfrage. Er zeigt, welche Operatoren SQL Server einsetzt, in welcher Reihenfolge er auf Tabellen zugreift, ob Indizes genutzt werden, wie viele Zeilen je Operator geschätzt und tatsächlich verarbeitet werden, und wo die höchsten Kosten anfallen. Wer Ausführungspläne lesen kann, sieht die Diagnose direkt – ohne auf externe Werkzeuge angewiesen zu sein.
Estimated vs. Actual Execution Plan
Der geschätzte Plan (Estimated Execution Plan) zeigt, was SQL Server tun will, ohne die Abfrage auszuführen. Er ist nützlich für die schnelle Vorab-Analyse. Der tatsächliche Plan (Actual Execution Plan) enthält zusätzlich die realen Zeilenzahlen und Laufzeitmessungen. Die wichtigste Vergleichsgröße ist die Differenz zwischen geschätzten und tatsächlichen Zeilen (Estimated Rows vs. Actual Rows): Eine große Abweichung zeigt eine ungenaue Kardinalitätsschätzung, die auf veraltete Statistiken oder fehlende Statistiken hinweist.
Schlüsseloperatoren und ihre Bedeutung
Table Scan bedeutet, dass SQL Server die gesamte Tabelle liest – fast immer ein Zeichen für einen fehlenden oder nicht nutzbaren Index. Clustered Index Scan ist ähnlich: der gesamte geclusterte Index wird durchsucht. Index Seek hingegen ist der erwünschte Zugriff: SQL Server navigiert direkt zu den relevanten Seiten. Key Lookup (Bookmark Lookup) taucht auf, wenn ein Non-Clustered Index genutzt wird, aber nicht alle benötigten Spalten enthält – SQL Server muss für jede Zeile zusätzlich in den geclusterten Index schauen. Viele Key Lookups bei gleichzeitig hoher Zeilenzahl sind ein klarer Hinweis darauf, dass INCLUDE-Spalten im Index fehlen.
Warnzeichen im Plan
Gelbe Ausrufezeichen im Plan sind explizite Warnungen: fehlende Statistiken, implizite Konvertierungen oder fehlende Indizes (Missing Index Hints). Diese Hinweise sollten immer untersucht werden. Parallelismus-Operatoren (Parallelism / Repartition Streams) zeigen, dass SQL Server mehrere Kerne nutzt – das ist nicht immer gewünscht und kann in OLTP-Systemen zu Locking-Problemen führen. Ein MAXDOP-Hint oder eine Ressourcen-Governor-Konfiguration kann das steuern.
-- Schlechter Plan: CONVERT verhindert Index-Nutzung -> Table Scan
SELECT OrderID, CustomerID, TotalAmount
FROM dbo.Orders
WHERE CONVERT(varchar(10), OrderDate, 104) = '01.06.2025';
-- Ausfuehrungsplan: Clustered Index Scan, hohe Logical Reads
-- Guter Plan: direktes Datums-Praedikat -> Index Seek
SELECT OrderID, CustomerID, TotalAmount
FROM dbo.Orders
WHERE OrderDate >= '2025-06-01'
AND OrderDate < '2025-06-02';
-- Ausfuehrungsplan: Index Seek auf idx_Orders_OrderDate, wenige Logical Reads
-- Hinweis: den tatsaechlichen Plan mit Laufzeitdaten anfordern
SET STATISTICS IO ON;
SET STATISTICS TIME ON;
-- Abfrage hier einfuegen
SET STATISTICS IO OFF;
SET STATISTICS TIME OFF;
-- Alternativ: XML-Plan aus dem Cache lesen (fuer Produktionsauswertung)
SELECT qp.query_plan,
qs.total_logical_reads,
qs.execution_count,
SUBSTRING(qt.text, 1, 200) AS query_snippet
FROM sys.dm_exec_query_stats AS qs
CROSS APPLY sys.dm_exec_sql_text(qs.sql_handle) AS qt
CROSS APPLY sys.dm_exec_query_plan(qs.plan_handle) AS qp
WHERE qt.text LIKE '%Orders%'
ORDER BY qs.total_logical_reads DESC;Der Vergleich zeigt, wie eine kleine Formulierungsänderung aus einem Table Scan einen Index Seek macht. Die CONVERT-Funktion auf der Spalte macht das Prädikat nicht-sargable: SQL Server kann den Index nicht nutzen, weil er nicht weiß, für welche Rohwerte die Konvertierung das gesuchte Ergebnis liefert.
Index-Strategie
Indizes sind das wichtigste Werkzeug für schnelle Lesezugriffe in SQL Server – aber nur, wenn sie richtig eingesetzt werden. Ein Index, der nicht genutzt wird, verbraucht Platz und verlangsamt INSERT/UPDATE/DELETE-Operationen unnötig. Ein fehlender Index führt zu vollen Scans über Millionen von Zeilen. Die Arbeit besteht darin, die richtige Balance zu finden: Welche Abfragen sind häufig und leseintensiv genug, um einen dedizierten Index zu rechtfertigen? Welche Indizes überlappen sich und können zusammengeführt werden?
Covering-Index und INCLUDE-Spalten
Ein Covering-Index enthält alle Spalten, die eine Abfrage benötigt – sowohl die Suchspalten (in der Schlüsselspalte) als auch die Ausgabespalten (als INCLUDE). Ein solcher Index ermöglicht einen Index-Only-Zugriff: SQL Server muss nicht mehr in den geclusterten Index zurückschauen (Key Lookup), weil alle benötigten Daten im Non-Clustered Index enthalten sind. Der Unterschied zwischen vielen Key Lookups und keinem Key Lookup ist bei häufig ausgeführten Abfragen erheblich.
Gefilterter Index
Ein gefilterter Index (Filtered Index) indiziert nur einen Teil des Bestands – nämlich genau die Zeilen, die einer WHERE-Bedingung entsprechen. Das ist besonders nützlich bei Spalten mit schiefer Verteilung: Wenn 95 Prozent der Bestellungen den Status 'abgeschlossen' haben und nur 5 Prozent 'offen' sind, aber fast alle Abfragen nach offenen Bestellungen filtern, ist ein gefilterter Index auf Status = 'offen' erheblich kleiner und damit schneller als ein vollständiger Index. Gleichzeitig besteht weniger Overhead bei Schreiboperationen auf die 95-Prozent-Mehrheit.
Columnstore-Index für analytische Abfragen
Für analytische Abfragen, die große Datenmengen aggregieren, bietet SQL Server den Columnstore-Index. Dabei werden Daten spaltenweise statt zeilenweise gespeichert, was für typische DWH-Abfragen (SELECT wenige Spalten, große Mengen, GROUP BY) eine erheblich bessere Kompression und deutlich geringere I/O-Last bedeutet. In kombinierten OLTP/OLAP-Szenarien kann ein Non-Clustered Columnstore-Index auf einer transaktionalen Tabelle analytische Abfragen um Größenordnungen beschleunigen, ohne den OLTP-Workload zu beeinträchtigen.
-- 1) Covering-Index: Schluessel + INCLUDE-Spalten vermeiden Key Lookup
CREATE NONCLUSTERED INDEX idx_Orders_Date_Covering
ON dbo.Orders (OrderDate, CustomerID)
INCLUDE (TotalAmount, OrderStatus);
-- Abfragen, die OrderDate/CustomerID filtern und TotalAmount/OrderStatus ausgeben,
-- benoetigen keinen zusaetzlichen Lookup in den Clustered Index.
-- 2) Gefilterter Index: nur offene Bestellungen indizieren
CREATE NONCLUSTERED INDEX idx_Orders_Open
ON dbo.Orders (CustomerID, OrderDate)
WHERE OrderStatus = 'OPEN';
-- Kleiner, schneller Index fuer den haeufigsten Abfragefall.
-- Bei INSERT/UPDATE auf abgeschlossene Bestellungen entsteht kein Overhead.
-- 3) Non-Clustered Columnstore fuer analytische Summen-Abfragen
CREATE NONCLUSTERED COLUMNSTORE INDEX nccs_Orders_Analytics
ON dbo.Orders (OrderDate, CustomerID, TotalAmount, OrderStatus);
-- Aggregationen (SUM, COUNT, AVG) ueber grosse Datenmengen profitieren von
-- spaltenweiser Speicherung und Batch-Verarbeitung.
-- 4) Index-Nutzung pruefen: welche Indizes werden nicht genutzt?
SELECT OBJECT_NAME(i.object_id) AS table_name,
i.name AS index_name,
i.type_desc,
ius.user_seeks,
ius.user_scans,
ius.user_lookups,
ius.user_updates
FROM sys.indexes AS i
LEFT JOIN sys.dm_db_index_usage_stats AS ius
ON ius.object_id = i.object_id
AND ius.index_id = i.index_id
AND ius.database_id = DB_ID()
WHERE i.type > 0 -- kein Heap
AND OBJECT_NAME(i.object_id) NOT LIKE 'sys%'
ORDER BY ius.user_seeks + ius.user_scans + ius.user_lookups ASC;sys.dm_db_index_usage_stats zeigt seit dem letzten Neustart, wie oft jeder Index für Seeks, Scans und Lookups genutzt wurde. Indizes mit user_seeks=0, user_scans=0, user_lookups=0, aber hohen user_updates sind Kandidaten für die Entfernung.
Statistiken und Parameter-Sniffing
Zwei der häufigsten und gleichzeitig am schwersten zu diagnostizierenden Performance-Probleme in SQL Server sind veraltete Statistiken und Parameter-Sniffing. Beide führen dazu, dass der Query Optimizer einen Plan wählt, der für den tatsächlichen Datenzustand schlecht geeignet ist – und beide sind mit den richtigen Werkzeugen identifizierbar und behebbar.
Warum Statistiken kritisch sind
Statistiken beschreiben die Werteverteilung in Tabellenspalten in Form von Histogrammen. Der Query Optimizer nutzt diese Histogramme, um zu schätzen, wie viele Zeilen ein Prädikat zurückgibt. Ist ein Histogramm veraltet – weil seit der letzten Aktualisierung viele Zeilen eingefügt, aktualisiert oder gelöscht wurden –, sind diese Schätzungen ungenau. Der Optimizer wählt dann möglicherweise einen Hash Join statt eines Nested Loop Join, oder er reserviert zu wenig Speicher für eine Sortieroperation und schreibt auf TempDB. Beides ist deutlich langsamer als ein gut informierter Plan.
Parameter-Sniffing: Ursache und Symptome
SQL Server kompiliert einen Plan beim ersten Aufruf einer gespeicherten Prozedur und speichert ihn im Plan Cache. Dieser Plan ist für die Parameter-Werte des ersten Aufrufs optimiert. Wenn nachfolgende Aufrufe mit sehr unterschiedlichen Parameter-Werten arbeiten – etwa ein Kunde mit 10 Bestellungen vs. ein Kunde mit 10 Millionen Bestellungen –, kann der gecachte Plan für die neuen Werte extrem suboptimal sein. Das Symptom ist eine Stored Procedure, die mal schnell und mal qualvoll langsam ist, ohne dass sich am Code etwas geändert hat. Der Query Store ist das beste Werkzeug zur Diagnose: Er zeigt, ob dieselbe Procedure verschiedene Pläne hatte und welcher Plan zu welchem Zeitpunkt aktiv war.
-- 1) Statistiken aktualisieren (mit vollstaendigem Scan fuer kritische Tabellen)
UPDATE STATISTICS dbo.Orders WITH FULLSCAN;
-- FULLSCAN liest alle Zeilen und liefert genaue Histogramme.
-- Standard-Sample kann bei schiefer Verteilung ungenaue Schaetzungen liefern.
-- 2) Alle Statistiken einer Datenbank aktualisieren (Wartungsskript)
EXEC sp_updatestats; -- verwendet adaptives Sampling, schnell aber weniger genau
-- Fuer kritische Tabellen: separater FULLSCAN-Aufruf empfohlen.
-- 3) OPTION (RECOMPILE) gegen Parameter-Sniffing
-- Zwingt SQL Server, fuer jeden Aufruf einen neuen Plan zu kompilieren.
-- Geeignet fuer Abfragen, die selten laufen und stark variierende Parameter haben.
CREATE OR ALTER PROCEDURE dbo.GetOrdersByCustomer
@CustomerID INT
AS
BEGIN
SELECT OrderID, OrderDate, TotalAmount
FROM dbo.Orders
WHERE CustomerID = @CustomerID
OPTION (RECOMPILE); -- kein Plan-Caching, immer frischer Plan
END;
-- 4) Query Store: regressive Plaene identifizieren
SELECT qsq.query_id,
qsrs.avg_duration / 1000 AS avg_ms,
qsrs.count_executions,
qsp.plan_id,
qsp.is_forced_plan,
TRY_CAST(qsp.query_plan AS XML) AS plan_xml
FROM sys.query_store_query AS qsq
JOIN sys.query_store_query_text AS qsqt ON qsqt.query_text_id = qsq.query_text_id
JOIN sys.query_store_plan AS qsp ON qsp.query_id = qsq.query_id
JOIN sys.query_store_runtime_stats AS qsrs ON qsrs.plan_id = qsp.plan_id
WHERE qsrs.avg_duration > 500000 -- Abfragen mit mehr als 500 ms Durchschnitt
ORDER BY qsrs.avg_duration DESC;OPTION (RECOMPILE) ist kein Allheilmittel – sie erhöht CPU-Last durch häufiges Kompilieren. Für hochfrequente Abfragen mit stabilen Parametern ist Plan Forcing über den Query Store die bessere Alternative: Der bekannte gute Plan wird erzwungen, ohne jedes Mal neu zu kompilieren.
Eine nachhaltige Statistikstrategie umfasst mehrere Elemente: automatische Aktualisierung ist eingeschaltet (AUTO_UPDATE_STATISTICS ON), für kritische Tabellen mit schnell wachsenden Beständen wird mit einem Schwellwert-Trace-Flag (TF 2371 oder die neue adaptive Threshold-Logik ab SQL Server 2016) gearbeitet, und bestimmte Tabellen erhalten regelmäßige FULLSCAN-Aktualisierungen im Wartungsfenster. Der Query Store ist aktiviert und so konfiguriert, dass eine ausreichende Historie für Planverläufe erhalten bleibt.
Tabellen-Partitionierung
Wenn Tabellen in den Bereich von zig bis hunderten Millionen Zeilen wachsen, stoßen herkömmliche Indexstrategien an Grenzen. Wartungsoperationen wie Index Rebuild oder STATISTICS UPDATE dauern Stunden, Ladeoperationen sperren die gesamte Tabelle, und Archivierungen erfordern aufwendige DELETE-Batches. Tabellen-Partitionierung löst diese Probleme strukturell, indem sie eine Tabelle intern in physisch getrennte Segmente aufteilt – für Abfragen und Anwendungen unsichtbar, für Wartung und Performance aber erheblich.
Eine Partitionierung erfolgt anhand einer Partitionsschlüsselspalte, typischerweise ein Datum oder ein Zeitstempel. SQL Server verteilt die Zeilen anhand einer Partitionsfunktion auf Partitionsschemas und physische Dateigruppen. Abfragen, die einen Datumsbereich filtern, profitieren von Partition Elimination: SQL Server liest nur die Partitionen, die den gesuchten Bereich abdecken, und überspringt alle anderen. Das reduziert I/O und logische Lesezugriffe erheblich.
Switch-basierte Archivierung und Beladung
Der größte operative Vorteil der Partitionierung liegt im Partition Switch. Eine neue Partition kann als separate Tabelle vorbefüllt, indiziert und dann per ALTER TABLE … SWITCH in Sekundenbruchteilen (metadata-only) in die Haupttabelle eingefügt werden. Umgekehrt lässt sich eine alte Partition ebenso schnell ausschalten und in eine Archivtabelle verschoben werden. Diese Switch-Operationen erfordern keine Datenbewegung und keine langen Sperren – ein kritischer Vorteil in hochverfügbaren Systemen.
Automatische Partitionserweiterung
In Projekten mit kontinuierlichem Datenzufluss ist eine automatische Partitionserweiterung sinnvoll: Ein SQL-Agent-Job prüft regelmäßig, ob die nächste Zeitperiode bereits als Partition existiert, und legt sie bei Bedarf an. So wächst die Tabelle kontrolliert, ohne dass manuelle Eingriffe nötig sind. Dieses Muster habe ich in einem E-Commerce-Projekt mit SCD2-Historisierung umgesetzt: Die Partitionierung nach Monat ermöglichte sowohl schnelle Beladung (Switch-In) als auch schnelle Archivierung älterer Historienbestände (Switch-Out).
-- 1) Partitionsfunktion: teilt Daten nach Monat auf
CREATE PARTITION FUNCTION pf_Orders_Monthly (DATE)
AS RANGE RIGHT FOR VALUES (
'2024-01-01','2024-02-01','2024-03-01','2024-04-01',
'2024-05-01','2024-06-01','2024-07-01','2024-08-01',
'2024-09-01','2024-10-01','2024-11-01','2024-12-01',
'2025-01-01','2025-02-01','2025-03-01','2025-04-01',
'2025-05-01','2025-06-01'
);
-- 2) Partitionsschema: jede Partition einer Dateigruppe zuordnen
CREATE PARTITION SCHEME ps_Orders_Monthly
AS PARTITION pf_Orders_Monthly
ALL TO ([PRIMARY]); -- vereinfacht: alle auf PRIMARY; produktiv separate FGs nutzen
-- 3) Partitionierte Tabelle anlegen
CREATE TABLE dbo.Orders_Partitioned (
OrderID BIGINT NOT NULL,
CustomerID INT NOT NULL,
OrderDate DATE NOT NULL,
TotalAmount DECIMAL(18,2) NOT NULL,
CONSTRAINT pk_Orders_Part PRIMARY KEY CLUSTERED (OrderDate, OrderID)
) ON ps_Orders_Monthly (OrderDate);
-- 4) Neue Partition fuer naechsten Monat hinzufuegen (Erweiterung)
ALTER PARTITION SCHEME ps_Orders_Monthly NEXT USED [PRIMARY];
ALTER PARTITION FUNCTION pf_Orders_Monthly() SPLIT RANGE ('2025-07-01');
-- 5) Schnelles Switch-In einer neuen Partition (kein Datentransfer, nur Metadaten)
-- Staging-Tabelle (gleiche Struktur, gleiche Dateigruppe) muss vorab beladenwerden:
ALTER TABLE dbo.Orders_Staging
SWITCH TO dbo.Orders_Partitioned PARTITION 19;
-- Dauert Millisekunden, keine langen Sperren auf der Haupttabelle.
-- 6) Partition Elimination pruefen
SELECT partition_number,
row_count,
reserved_page_count * 8 / 1024 AS reserved_MB
FROM sys.dm_db_partition_stats
WHERE object_id = OBJECT_ID('dbo.Orders_Partitioned')
ORDER BY partition_number;Der SPLIT RANGE am Ende fügt eine neue Partition hinzu, ohne die Tabelle zu sperren. SWITCH IN/OUT ist der entscheidende Vorteil der Partitionierung: Statt stundenlanger DELETE-Batches eine metadaten-only-Operation in Millisekunden.
SSIS-Performance
SQL Server Integration Services ist das ETL-Werkzeug für viele Ladeprozesse in SQL-Server-Umgebungen. Performance-Probleme in SSIS entstehen häufig nicht durch den Datenfluss selbst, sondern durch schlecht konfigurierte Quell- und Zielkomponenten, fehlende Parallelisierung, unnötige Sortierungen und den Einsatz von Blocking-Transformationen dort, wo Streaming-Transformationen ausreichen würden.
Blocking vs. Streaming Transformationen
In SSIS unterscheidet man zwischen Fully Blocking-, Partially Blocking- und Row-by-Row-Transformationen. Fully Blocking-Transformationen wie Sort oder Aggregate puffern alle eingehenden Zeilen, bevor sie die erste Ausgabezeile erzeugen. Das bedeutet hohen Speicherverbrauch und einen vollständigen Stau im Datenfluss. Wer eine Sortierung im Datenfluss vermeiden kann – etwa indem ORDER BY in der SQL-Quellabfrage oder im Merge Join durch einen vorsortiert gelieferten Bestand ersetzt wird –, gewinnt erheblich an Durchsatz und verringert den Speicherbedarf.
OLE DB Destination und Batch-Größe
Die OLE DB Destination schreibt Daten ins Ziel. Die entscheidenden Einstellungen sind der Data Access Mode (Fast Load ist fast immer richtig), die Batch-Größe (rows per batch) und die Anzahl der Zeilen pro Commit. Zu kleine Batches erzeugen hohen Overhead durch viele kleine Transaktionen, zu große Batches können den Transaktionslog belasten und Sperren verlängern. Ein guter Ausgangswert ist 10.000 bis 50.000 Zeilen pro Batch, je nach Zeilengröße und Log-Konfiguration. MaxInsertCommitSize steuert, wie viele Zeilen pro Commit übergeben werden – 0 bedeutet, dass der gesamte Batch in einer Transaktion landet.
Parallelisierung und Datenfluss-Partitionierung
SSIS nutzt mehrere Threads innerhalb eines Datenflusses automatisch. Mit dem Property EngineThreads lässt sich die Anzahl der Threads steuern. Darüber hinaus können mehrere Data Flow Tasks parallelisiert werden, indem sie als Kinder eines Sequence Containers mit aktiviertem MaxConcurrentExecutables ausgeführt werden. In Projekten habe ich SSIS-Strecken grundlegend redesignt und dabei Parallelisierung eingeführt, die die Gesamtlaufzeit signifikant reduziert hat.
-- Waehrend eines SSIS-Laufs: aktuelle Sperren und Wartetypen auf dem Zielserver pruefen
SELECT
r.session_id,
r.status,
r.wait_type,
r.wait_time AS wait_ms,
r.logical_reads,
r.writes,
SUBSTRING(t.text, 1, 200) AS query_snippet,
DB_NAME(r.database_id) AS db_name
FROM sys.dm_exec_requests AS r
CROSS APPLY sys.dm_exec_sql_text(r.sql_handle) AS t
WHERE r.session_id <> @@SPID
AND r.status IN ('running','suspended')
ORDER BY r.wait_time DESC;
-- Typische SSIS-Wartetypen und ihre Bedeutung:
-- WRITELOG : Transaktionslog-I/O (Log-Datei zu langsam oder Batch zu gross)
-- PAGEIOLATCH_EX : Datenseiten-I/O beim Schreiben (Storage-Engpass)
-- LCK_M_* : Sperrkonflikte (SSIS-Ziel vs. parallele Lesezugriffe)
-- ASYNC_IO_COMPLETION: asynchrone I/O-Vorgaenge (normal bei Fast-Load)
-- Empfehlung: SSIS-Ladevorgang in Ladefenster legen und Tabellensperre
-- (TABLOCK-Hint in OLE DB Destination) nur dann aktivieren, wenn
-- keine parallelen Lesezugriffe auf die Zieltabelle stattfinden.WRITELOG als dominanter Wartetyp während eines SSIS-Laufs signalisiert, dass die Commit-Frequenz zu hoch oder das Transaktionslog zu langsam ist. Vergrößerung von MaxInsertCommitSize und Umstellung auf Fast Load lösen dieses Problem in den meisten Fällen.
Wait Stats und Monitoring
Wait Statistics sind die systemweiteste und gleichzeitig präziseste Methode, um Engpässe in SQL Server zu identifizieren. SQL Server protokolliert für jeden Thread, der auf etwas warten muss, den Wartetyp und die Wartezeit. Die Aggregation dieser Daten in sys.dm_os_wait_stats zeigt, worauf das System insgesamt am längsten wartet – und damit, wo der tatsächliche Engpass liegt, bevor man sich überhaupt in einzelne Abfragen vertieft.
Die wichtigsten Wartetypen
PAGEIOLATCH_SH und PAGEIOLATCH_EX signalisieren I/O-Engpässe: SQL Server wartet darauf, dass Datenseiten vom Speicher gelesen werden. Ist dieser Wartetyp dominant, hilft mehr RAM (größerer Buffer Pool) oder schnellerer Storage (SSD/NVMe). CXPACKET und CXCONSUMER stehen für parallele Abfrageausführung: Threads warten aufeinander. Moderate CXPACKET-Werte sind normal; hohe Werte deuten auf schief-verteilte Daten oder ungeeignetes MAXDOP hin. LCK_M_S, LCK_M_U und LCK_M_X stehen für Sperrkonflikte: Lesende und schreibende Transaktionen blockieren sich gegenseitig. WRITELOG signalisiert, dass der Transaktionslog-Schreibvorgang der Engpass ist.
Query Store als historisches Monitoring
Der Query Store, eingeführt in SQL Server 2016 und Standard ab SQL Server 2019, speichert Abfragen, Pläne und Laufzeitstatistiken dauerhaft in der Datenbank. Das ermöglicht historische Analysen: Welche Abfrage hatte letzte Woche eine Planregression? Welcher Plan war vor dem letzten Index-Rebuild aktiv? Mit Plan Forcing lässt sich ein bekannt guter Plan dauerhaft erzwingen – ohne Eingriff in den Anwendungscode. Das ist besonders wertvoll bei fremden Anwendungen, deren Abfragecode nicht zugänglich oder nicht änderbar ist.
Regelmäßiges Wartungsregime
Neben der reaktiven Diagnose gehört ein proaktives Wartungsregime zu einer gesunden SQL-Server-Umgebung. Das umfasst regelmäßige Index-Reorganisierungen und -Rebuilds nach Fragmentierungsgrad (nicht nach starrem Zeitplan), Statistikaktualisierungen mit FULLSCAN für kritische Tabellen, Überprüfung des Query Stores auf Regressionen und ein wöchentliches oder monatliches Review der Top-Wait-Stats-Kategorien. Erst diese Regelmäßigkeit verhindert, dass sich Performance-Probleme schleichend aufbauen, bis sie akut werden.
-- Top-20-Wartetypen seit letztem Neustart (normalisiert auf Prozent)
WITH waits AS (
SELECT
wait_type,
waiting_tasks_count,
wait_time_ms,
max_wait_time_ms,
signal_wait_time_ms,
wait_time_ms - signal_wait_time_ms AS resource_wait_ms
FROM sys.dm_os_wait_stats
WHERE wait_type NOT IN ( -- Leerlauf-Wartetypen herausfiltern
'SLEEP_TASK','BROKER_TO_FLUSH','BROKER_TASK_STOP','CLR_AUTO_EVENT',
'DISPATCHER_QUEUE_SEMAPHORE','FT_IFTS_SCHEDULER_IDLE_WAIT',
'HADR_FILESTREAM_IOMGR_IOCOMPLETION','HADR_WORK_QUEUE',
'LAZYWRITER_SLEEP','LOGMGR_QUEUE','ONDEMAND_TASK_QUEUE',
'REQUEST_FOR_DEADLOCK_SEARCH','RESOURCE_QUEUE','SERVER_IDLE_CHECK',
'SLEEP_DBSTARTUP','SLEEP_DCOMSTARTUP','SLEEP_MASTERDBREADY',
'SLEEP_MASTERMDREADY','SLEEP_MASTERUPGRADED','SLEEP_MSDBSTARTUP',
'SLEEP_TEMPDBSTARTUP','SNI_HTTP_ACCEPT','SP_SERVER_DIAGNOSTICS_SLEEP',
'SQLTRACE_BUFFER_FLUSH','SQLTRACE_INCREMENTAL_FLUSH_SLEEP',
'WAIT_XTP_OFFLINE_CKPT_NEW_LOG','WAITFOR','XE_DISPATCHER_WAIT',
'XE_TIMER_EVENT','BROKER_EVENTHANDLER','CHECKPOINT_QUEUE',
'DBMIRROR_EVENTS_QUEUE','SQLTRACE_WAIT_ENTRIES'
)
)
SELECT TOP 20
wait_type,
waiting_tasks_count,
wait_time_ms,
max_wait_time_ms,
CAST(100.0 * wait_time_ms
/ SUM(wait_time_ms) OVER () AS DECIMAL(5,2)) AS pct_total,
resource_wait_ms,
signal_wait_time_ms AS cpu_queue_ms
FROM waits
ORDER BY wait_time_ms DESC;Die Idle-Wartetypen werden ausgefiltert, weil SQL Server in Ruhephasen auf sie wartet und sie das Bild verfälschen würden. Die verbleibenden Wartetypen zeigen den echten Engpass: I/O, Locking, Parallelismus oder CPU-Queue.
Vorgehen in der Zusammenarbeit
Performance-Tuning ist keine isolierte Aktivität, sondern eine Zusammenarbeit mit dem Team, das die Systeme kennt und betreibt. Ich bringe die analytischen Werkzeuge und die Diagnosekompetenz mit; das Projektteam bringt das fachliche Wissen über die Abläufe, die Zeitfenster und die Kritikalität der betroffenen Systeme. Aus dieser Kombination entstehen Maßnahmen, die technisch fundiert und im Betrieb umsetzbar sind.
Typischer Projekteinstieg
In der Regel beginne ich mit einem Assessment: Ich verschaffe mir einen Überblick über die SQL-Server-Umgebung, analysiere Wait Statistics, die teuersten Abfragen aus sys.dm_exec_query_stats und den Query Store, prüfe den Index-Bestand und die Statistikaktualität. Das Ergebnis ist eine priorisierte Liste von Engpässen und Maßnahmen. Dieser erste Schritt dauert typischerweise ein bis drei Tage – je nach Umgebungsgröße – und liefert ein klares Bild, bevor aufwendigere Maßnahmen in Angriff genommen werden.
Iterative Umsetzung
Die Umsetzung erfolgt iterativ und messbar. Jede Maßnahme wird vorher begründet, nach der Umsetzung gemessen und dokumentiert. So entsteht ein nachvollziehbares Performance-Log, das zeigt, welche Maßnahme welchen Effekt hatte. Das ist nicht nur für das aktuelle Projekt wertvoll, sondern auch für das langfristige Verständnis des Systems: Warum hat man damals diesen Index angelegt? Welches Problem sollte er lösen?
- Assessment: Wait Stats, Top-Abfragen, Index-Bestand, Statistikaktualität
- Priorisierung: Maßnahmen nach Aufwand/Wirkung-Verhältnis sortieren
- Umsetzung: Iterativ, jede Maßnahme wird gemessen und dokumentiert
- Verifikation: Vorher-/Nachher-Vergleich mit denselben Werkzeugen
- Wissenstransfer: Team mit Diagnosewerkzeugen und Mustern vertraut machen
Ich arbeite remote, hybrid und vor Ort. Gerade bei Performance-Projekten ist ein enger Austausch mit dem Betriebsteam wichtig, weil viele Maßnahmen im Wartungsfenster durchgeführt werden müssen und weil das Team anschließend in der Lage sein soll, denselben diagnostischen Blick selbst anzuwenden. Wissenstransfer ist für mich kein Zusatzangebot, sondern Teil der Lieferung.
Typische Leistungen rund um SQL Performance Tuning
Je nach Ausgangslage und Projektziel übernehme ich unterschiedliche Aufgaben – von der einmaligen Notfallanalyse bis zum mehrstufigen Performance-Programm, das eine Umgebung dauerhaft auf ein neues Niveau hebt.
- Performance-Assessment: Wait Stats, Top-Abfragen, Index- und Statistikanalyse
- Ausführungsplan-Analyse und Abfrageoptimierung für kritische Workloads
- Index-Strategie: Entwurf, Umsetzung und Bereinigung redundanter Indizes
- Statistikstrategie: Wartungsplan, FULLSCAN-Zeitpläne, Query-Store-Konfiguration
- Parameter-Sniffing-Diagnose und Behebung (Recompile, Plan Forcing, Query Store)
- Tabellen-Partitionierung: Design, Umsetzung und automatische Erweiterung
- Columnstore-Index-Einführung für analytische Workloads
- SSIS-Performance-Optimierung: Datenfluss-Redesign, Parallelisierung, Batch-Größen
- TempDB-Konfiguration und Spill-Diagnose
- Wait-Stats-Monitoring und historisches Performance-Tracking
- Query-Store-Konfiguration und Planregression-Management
- Wissenstransfer und Coaching für Entwicklungsteams
Viele Performance-Probleme sind nicht isoliert: Eine langsame Abfrage ist oft Symptom einer fehlenden Index-Strategie, die ihrerseits aus einer fehlenden Monitoring-Praxis folgt. Ich schaue deshalb nicht nur auf die akut brennende Stelle, sondern nehme die gesamte Umgebung in den Blick – und trenne, was sofort behoben werden muss, von dem, was mittel- und langfristig zu einer gesunden Performance-Basis beiträgt.
Die Bandbreite meiner SQL-Server-Erfahrung – von SQL Server 2000 bis 2025, von OLTP über DWH bis SSIS, von kleinen Einzelsystemen bis zu Umgebungen mit rund 80 virtualisierten Servern – erlaubt es mir, schnell zu beurteilen, welche Maßnahmen in welchem Kontext realistisch und wirksam sind. Nicht jede Partitionierung lohnt sich, nicht jeder Columnstore-Index ist ein Gewinn – der Kontext entscheidet, und dieser Kontext ist immer die konkrete Workload-Charakteristik des jeweiligen Systems.
Ausgewählte anonymisierte Referenzprojekte
Sparkasse / Finanzdienstleister
Ablösung bestehender Java-basierter Ladeprozesse durch neu konzipierte SSIS-Strecken, einschließlich Textdatei-Loads und SSDT-Deployment über PowerShell. Gleichzeitig systematische Performanceoptimierung der neuen SSIS-Strecken: Redesign der Datenflüsse, Parallelisierung, Batch-Größen-Konfiguration und Reduzierung von Blocking-Transformationen. Ergebnis: signifikant kürzere Ladefenster und stabile Betriebsprozesse.
Loyalty / Handel / Clearing
Umfassende Performanceanalyse einer Clearing-Plattform mit hohem Transaktionsvolumen: Wait-Stats-Analyse, Ausführungsplan-Review für kritische Clearing-Abfragen, Index-Optimierung und Statistikstrategie. Ergänzend SSIS-Performance-Tuning für Batch-Ladevorgänge sowie Aufbau von Power-BI-Datenmodellen mit Row-Level-Security.
Handel / E-Commerce
Entwurf und Umsetzung einer monatsbasierten Tabellen-Partitionierung für eine wachsende Bestellhistorie mit SCD2-Historisierung. Implementierung automatischer Partitionserweiterung über einen SQL-Agent-Job. Switch-basierte Beladung und Archivierung reduzierten die Ladezeiten und beseitigten lange Tabellensperren im Produktionsbetrieb.
Textil- / Servicedienstleister
Aufbau und Optimierung von ETL-Strecken in einer hybriden Umgebung aus SQL Server und Azure Synapse. Performance-Analyse bestehender SSIS-Pakete, gezielte Überarbeitung von Datenflüssen und Reduzierung redundanter Ladeschritte. Anbindung an Power BI mit optimierten Datenmodellen sowie Maßnahmen zur Kostenreduktion in der Azure-Umgebung.
Häufige Fragen zum SQL Performance Tuning
Wie läuft eine Performance-Analyse ab?
Ich beginne mit einer Baseline-Messung: Wait Statistics auf Systemebene, Top-Abfragen aus sys.dm_exec_query_stats und einem Blick in den Query Store. Daraus ergibt sich eine priorisierte Liste von Engpässen. Dann folgen Ausführungsplan-Analyse für die teuersten Abfragen, Index-Review und Statistikprüfung. Jede Maßnahme wird vor und nach der Umsetzung gemessen.
Welche SQL-Server-Versionen decken Sie ab?
SQL Server 2000 bis 2025. Die Diagnose- und Optimierungswerkzeuge sind über Versionen hinweg weitgehend konsistent; neuere Versionen bieten zusätzliche Möglichkeiten wie den Query Store (ab 2016) oder Intelligent Query Processing (ab 2019), die ich gezielt einsetze, wo sie verfügbar sind.
Was ist Parameter-Sniffing, und wie beheben Sie es?
SQL Server speichert beim ersten Aufruf einer Stored Procedure einen Plan, der für den ersten Parameter-Wert optimiert ist. Dieser Plan kann für andere Werte suboptimal sein. Diagnose erfolgt über den Query Store. Lösungsansätze: OPTION (RECOMPILE) für selten ausgeführte Prozeduren mit stark variierenden Parametern, Plan Forcing über den Query Store für bekannt gute Pläne, oder Überarbeitung der Abfrage.
Wann lohnt sich Tabellen-Partitionierung?
Partitionierung lohnt sich, wenn Tabellen in den Bereich ab ca. 50–100 Millionen Zeilen wachsen, wenn Wartungsoperationen (Index Rebuild, Statistik-Update) inakzeptabel lang dauern, wenn Switch-basierte Beladung und Archivierung benötigt werden oder wenn Abfragen typischerweise einen Zeitraumfilter haben, der Partition Elimination ermöglicht.
Können Sie auch SSIS-Performance-Probleme lösen?
Ja. SSIS-Performance-Tuning umfasst Datenfluss-Redesign, Parallelisierung, Batch-Größen-Konfiguration, Vermeidung von Blocking-Transformationen und Optimierung der Ziel-Konfiguration (OLE DB Destination Fast Load, MaxInsertCommitSize). Oft liegt der eigentliche Engpass aber auf der Datenbankseite – schlechte Indizes auf dem Ziel oder fehlende Indizes auf der Quelle.
Wie nachhaltig sind die Optimierungsmaßnahmen?
Nachhaltigkeit entsteht durch Monitoring. Ich richte regelmäßige Wait-Stats-Snapshots ein, konfiguriere den Query Store und übergebe dem Team Diagnoseabfragen, mit denen es selbst erkennen kann, wenn sich Probleme aufbauen. Das Ziel ist, dass das Team nach dem Projekt eigenständig in der Lage ist, Performance-Engpässe zu diagnostizieren.
Arbeiten Sie auch remote?
Ja, vollständig remote ist möglich. Performance-Analysen und Index-Optimierungen lassen sich effektiv über Remote-Datenbankzugang und Screensharing durchführen. Für strukturelle Maßnahmen wie Partitionierungen, die im Wartungsfenster stattfinden, ist gelegentliche Abstimmung vor Ort hilfreich, aber nicht zwingend.
In welchen Sprachen können wir zusammenarbeiten?
Auf Deutsch, Englisch und Portugiesisch – jeweils fließend, auch in technischen Diskussionen über Ausführungspläne, DMV-Ausgaben und Architekturentscheidungen.