Von Stefan Hufnagel auf Donnerstag, 20. Mai 2021
Kategorie: Data Management

SQL-Server-Replikation: Umständliche Fehlersuche nach dem „Arithmetic overflow“

Ausgangslage:

Ein Kunde berichtete, dass seine Replikation ausgefallen sei. Können wir helfen?

Bestandsaufnahme:

Ein SQL Server 2000 replizierte via push Replikation alle Transaktionen auf einen SQL Server 2012. Dies lief seit langer Zeit problemlos, aber jetzt eben nicht mehr. Da die Daten auf Seite des SQL Server 2012 nicht mehr aktualisiert wurden, konnte auf den abhängigen Systemen nicht mehr gearbeitet werden.
Die Fehlermeldung im Relikationsmonitor besagte: „Arithmetic overflow error converting expression to INT". Nur leider nicht in welcher Tabelle, View oder sonstigem Objekt.

Analyse:

Wir nahmen mit dem Profiler verschiedene Traces auf, um zu sehen, an welcher Stelle der Fehler auftrat. Wirklich erhellend war es leider nicht. Es wurden 200 Transaktionen begonnen, dann kam der Abbruch.
Eine parallele Recherche, ob dies ein bekannter Fehler ist, ergab, dass es sich um ein Problem mit Identity-Werten handeln könnte. Irgendwann ist das Limit erreicht, hier 2.147.483.648. Es wurde jede Tabelle der Datenbank geprüft, keine enthielt einen Identity-Wert.
Auch wurden alle Tabellen der Datenbank auf große Werte geprüft, aber wir waren nicht einmal nah dran, der Maximalwert lag bei ca. 2.000.000.

Der Aufruf von DBCC CheckDB lieferte zumindest das Ergebnis, dass keine Korruption vorlag.

Leider stand kein Testsystem zur Verfügung, um zu testen, ob eine erneute Replikation auch auf Fehler laufen würde. Wenigstens konnten wir eingrenzen, dass der Fehler auf der Seite des Distributors liegen musste.

Doch wie kann ein Wert, der in der DB schon angelegt ist, die Grenze des Datentyps sprengen? Da hätte es vorher schon zu einem Fehler kommen müssen.

Ein weiterer hinzugezogener Kollege fand alte Blogeinträge mit Hinweisen, dass es zu Problemen mit der Replikation kommen kann, wenn in der Tabelle [distribution].[dbo].[MSdistribution_history] in der Spalte [current_delivery_latency] zu hohe Werte stehen. Nach einem Backup der Datenbank passten wir die Werte an, aber erfolglos. Auch lagen die Werte noch weit unter 2.000.000.000.
Ein weiterer Neustart des Servers änderte nichts an der Fehlermeldung.

Problemlösung:

Zufällig scrollte der Kollege noch mal durch die Tabelle [MSdistribution_history]. Aus dem Augenwinkel sprang mir ein Wert ins Auge: 2.147.483.648! „Hey Leute, ist das nicht der Wert, den wir suchen?" Er war es! Und zwar in der Spalte [total_delivered_commands]. Der Kunde klärte auf, dass die Replikation ja schon lange nicht mehr neu aufgesetzt wurde, sondern einfach nur lief. Seit mehreren Jahren. Bis jetzt. Augenscheinlich wurden über 2 Mrd. Transaktionen abgearbeitet.

Wir überlegten, den Datentyp der Spalte auf BIGINT zu erweitern, da er in aktuellen SQL-Server-Versionen schon diesen Datentyp hat. Da dieser Wert jedoch von einer Prozedur befüllt wird, die als Übergabeparameter INT benutzt, war dies keine geeignete Lösung. Die Prozedur umschreiben hielten wir auch nicht für optimal.

Wir entschieden uns dafür, den Wert in der Spalte [total_delivered_commands] zurückzusetzen und die Replikation nochmals neu zu starten. Gesagt, getan! Als wäre nichts gewesen lief die Replikation wieder an und alle Daten wurden aktualisiert.

Fazit:

Mit einer sprechenden Fehlermeldung, also dem Hinweis, in welchem Objekt der Überlauf stattfand, hätte die Problemlösung stark beschleunigt werden können. Statt sich mehrfach durch alle Tabellen der Datenbank zu wühlen, wäre ein direkter Blick in die Systemdatenbank [distribution] und in die Tabelle [MSdistribution_history] zielführender gewesen. So mussten wir im Ausschlussverfahren erst all das finden, was es nicht war. Das mag bei Sherlock Holmes immer funktionieren, bei produktionsbehindernden Ausfällen bevorzuge ich jedoch eine zielgerichtete Lösung.

Kommentare hinterlassen