Schema-Refactoring in SQL Server unter Last
Umfangreiche Schema-Refactorings an einer produktiven Datenbank mit 800 Millionen Rechnungsdatensätzen — schwierig war nie das Schema, sondern das Sperrverhalten.
Eine Migrationsstrategie, die diesem Datenvolumen standhielt — gefunden, indem mehrere andere getestet und verworfen wurden.
Das Problem
Das Schema unter der Loyalty-Plattform musste sich ändern: große, strukturelle Refactorings an Tabellen mit 800 Millionen Rechnungsdatensätzen, in einer Datenbank, die sich nicht so lange offline nehmen ließ, wie der naheliegende Weg gebraucht hätte.
Bei einer kleinen Datenbank ist das ein Nachmittag. In dieser Größenordnung ist die Schemaänderung die leichte Hälfte. Die schwierige ist, dass jede Strategie irgendwo Sperren hält — und die falsche Sperre an der falschen Stelle legt das Produkt lahm.
Der Aufwand lag kaum im Schreiben des DDL, sondern darin, einen Weg zu finden, es anzuwenden.
Erste Versuche liefen wiederholt in Sperr- und Blockierungsprobleme: Die Migration nahm eine Sperre, die die Anwendung ebenfalls brauchte, beide warteten aufeinander, und das Produkt wurde langsam. Ich habe mehrere Migrationsstrategien durchgearbeitet und jede gegen das reale Datenvolumen getestet statt gegen eine verkleinerte Kopie — das relevante Verhalten zeigt sich erst in dieser Größe.
Konkret hieß das:
- Aus den Systemtabellen lesen, was die Datenbank während einer Migration tatsächlich tut, statt es von außen zu vermuten.
- Änderungen in Schritte zerlegen, die ihre Sperren jeweils nur kurz halten, statt eines Statements mit einer langen Sperre.
- Backfill und Umschaltung trennen, damit der langlaufende Teil nie im Pfad einer Benutzeranfrage liegt.
- Eine langsamere Migration gegen ein kürzeres Blocking-Fenster eintauschen — worauf fast jede Variante dieses Problems hinausläuft.
Das ist die Arbeit, zu der ich am liebsten befragt werde. Sie ist konkret, sie ist erst schiefgegangen und dann gelungen, und ich kann zu jeder verworfenen Strategie sagen, warum sie verworfen wurde.