By Frank Kalis
Gerade wenn man denkt, man versteht was so um einen herum vor sich geht und hat eine gewisse Einsicht in SQL Server, kommt es anders, als man denkt und endet in dem, was die Engländer so nett "Facepalm" nennen.
Hintergrund: Unsere Produktionsdatenbank ist auf einem SQL Server 2005 (Jaja, ich weiss...). Unsere Entwicklungsdatenbanken sind auf SQL Server 2008 im Kompatibilitätsgrad 9.0 (Jaja, ich weiss...).
Bis vor ein paar Tagen habe ich mir keine Gedanken gemacht, was genau "Kompatibilitätsgrad" eigentlich ist, beziehungsweise war der Meinung, dass ich verstehe, was das ist. Bis ich dann während eines Releases ein Aha-Erlebnis hatte.
Eines der Dinge, die sich zwischen SQL Server 2005 und SQL Server 2008 geändert haben, war, dass es mit 2008 möglich ist, eine Variable zu initialisieren und ihr direkt einen Wert zuzuweisen. Also, etwas in der Richtung:
DECLARE @i int = 1;
SELECT
compatibility_level, @i AS WTF
FROM
sys.databases
WHERE
name = DB_NAME();
Unter SQL Server 2005 wird so was gnadenlos mit einem
Msg 139, Level 15, State 1, Line 0
Cannot assign a default value to a local variable.
Msg 137, Level 15, State 2, Line 4
Must declare the scalar variable "@i".
quittiert.
Meine feste Überzeugung war, das dies auch der Fall sei, bei einer Datenbank im 90 Kompatibilitätsgrad auf einer 2008er Instanz. Haha...
Als der DBA mein Releaseskript laufen lies, kam genau dieser Fehler auf, den ich während der Erstellung ebendieses Skriptes nicht erhalten habe. Nun, das Release-Skript zu fixen, damit zunächst einmal der Release sauber über die Bühne gehen konnte, war trivial. Nachdem das erledigt war, ging es auf Spurensuche. Und siehe da! Der obige Batch, der gerade eben noch auf Fehler gelaufen war, gab dieses Ergebnis in der Datenbank zurück, die ich für die Erstellung meines Release-Skriptes verwendet habe:
DECLARE @i int = 1;
SELECT
compatibility_level, @i AS WTF
FROM
sys.databases
WHERE
name = DB_NAME();
compatibility_level WTF
------------------- -----------
90 1
(1 row(s) affected)
Was zum Teufel war hier los? Kann man sich denn auf nichts mehr verlassen? Das sollte doch eigentlich nicht möglich sein. Doch! Man muss halt nur genau lesen, was in der Dokumentation steht. In TechNet steht im Thema ALTER DATABASE-Kompatibilitätsgrad (Transact-SQL):
Der Kompatibilitätsgrad bietet nur partielle Abwärtskompatibilität mit früheren Versionen von SQL Server. Verwenden Sie den Kompatibilitätsgrad als vorläufige Migrationshilfe, um versionsbedingte Unterschiede in den Verhaltensweisen zu umgehen, die über die jeweilige Einstellung für den Kompatibilitätsgrad gesteuert werden. Wenn sich Verhaltensunterschiede in SQL Server 2008 auf vorhandene SQL Server-Anwendungen auswirken, sollten Sie die Anwendung konvertieren, damit sie ordnungsgemäß funktioniert.
Vereinfacht ausgedrückt heisst das nun, dass der Kompatibilitätsgrad sich NUR auf Features auswirkt, die in beiden Version von SQL Server vorhanden sind und bei denen sich das Verhalten zwischen diesen Versionen geändert hat. Durch das Setzen des Kompatibilitätsgrades wird sichergestellt, dass das Verhalten des Features auf der höheren Version von SQL Server identisch ist mit dem Verhalten des Features in der niedrigeren Version. Es ist keine Garantie dafür, dass das, was man auf einer höheren SQL Server Version entwickelt auch auf eine niedrigere Version deployen kann.
Zu meiner Ehrrettung muss ich sagen, dass ich die Änderung die dieses DECLARE @variable = Wert beinhaltete nicht kodiert habe. Allerdings ist es mir aber auch nicht aufgefallen, als ich das Change-Skript erstellt habe. :-(
Lesson learned...