Problembehandlung bei Fehlern und Warnungen zu Abfrageausdrücken

Es kann vorkommen, dass SQL Server 2008 Ausdrücke in Abfragen schneller als SQL Server 2000 auswertet. Dieses Verhalten bietet die folgenden wichtigen Vorteile:

  • Indizes für berechnete Spalten können Ausdrücken in einer Abfrage zugeordnet werden, die mit dem berechneten Spaltenausdruck übereinstimmen.

  • Die redundante Berechnung der Ausdrucksergebnisse wird verhindert.

Allerdings können je nach Art der Abfrage und der Daten in der Datenbank Laufzeitausnahmen in SQL Server 2008 auftreten, wenn in der Abfrage ein unsicherer Ausdruck vorhanden ist. Zu diesen Laufzeitausnahmen gehören folgende Ausnahmen:

  • Arithmetische Ausnahmen: Division durch Null, Überlauf und Unterlauf.

  • Konvertierungsfehler, wie z. B. der Verlust der Genauigkeit und der Versuch, eine nicht numerische Zeichenfolge in eine Zahl zu konvertieren.

  • Aggregation über eine Menge von Werten, für die nicht sichergestellt ist, dass alle Werte ungleich NULL sind.

In SQL Server 2000 kann es vorkommen, dass diese Ausnahmen in einer bestimmten Anwendung nicht auftreten, die bestimmte Daten verwendet. Ein Abfrageplan, der aufgrund einer geänderten Statistik geändert wird, kann jedoch in SQL Server 2008 zu einer Ausnahme führen. Diese Laufzeitausnahmen können durch Einschließen bedingter Ausdrücke in die Abfrage, wie NULLIF oder CASE, verhindert werden.

Wichtiger HinweisWichtig

Ausdrücke, die in einer Suchbedingung, einer Auswahlliste oder an irgendeiner anderen Stelle innerhalb einer Abfrage erscheinen, können in einen oder mehrere unabhängige Ausdrücke unterteilt und neu organisiert werden. SQL Server kann diese unabhängigen Ausdrücke in jeder beliebigen Reihenfolge zueinander auswerten.. Filtervorgänge, einschließlich Verknüpfungen, werden nicht unbedingt vor dem Berechnen der Ergebnisspalten angewendet.

Im folgenden Beispiel kann der Ausdruck x/y in der Auswahlliste zu jedem beliebigen Zeitpunkt ausgewertet werden, selbst bei Zeilen, die letztendlich nicht als Ausgabe für die Abfrage geeignet sind.

USE tempdb
GO
IF OBJECT_ID('T','U') IS NOT NULL
    DROP TABLE T
IF OBJECT_ID('S','U') IS NOT NULL
    DROP TABLE S
GO
CREATE TABLE T(x float, y float, z nvarchar(30))
CREATE TABLE S(a float, b float)
GO
INSERT INTO T VALUES (1, 0, 'unknown')
INSERT INTO T VALUES(1, 2, '10')
GO
INSERT INTO S VALUES (1, 1)
INSERT INTO S VALUES (1, 2)
INSERT INTO S VALUES (1, 3)
INSERT INTO S VALUES (1, 4)
INSERT INTO S VALUES (1, 5)

Die folgende Abfrage erzeugt in SQL Server 2008 einen Fehler, wird jedoch in SQL Server 2000 ausgeführt.

SELECT x/y FROM T INNER JOIN S ON x = a AND y > b
OPTION(HASH JOIN)

Die Abfrage erzeugt einen Fehler, weil der x/y-Ausdruck einen Fehler aufgrund einer Division durch Null verursacht, wenn er für y=0 bewertet wird.

Im folgenden Beispiel wird eine Lösung gezeigt, die ein erfolgreiches Ausführen der Abfrage zulässt.

SELECT x/NULLIF(y,0) FROM T INNER JOIN S ON x = a AND y > b
OPTION(HASH JOIN)

Der Ausdruck NULLIF(y,0) gibt NULL bei y = 0 zurück. Andernfalls gibt der Ausdruck den Wert für y zurück. Der Ausdruck x/NULL ergibt NULL; es tritt keine Ausnahme auf.

Im folgenden Beispiel werden Zeichendaten in numerische Typen konvertiert.

SELECT CONVERT(tinyint, z) FROM T INNER JOIN S ON x = a AND y > b
OPTION(HASH JOIN)

Die Abfrage erzeugt einen Konvertierungsfehler beim Konvertieren der Zeichenfolge 'unknown' in einen Zahlenwert des Typs tinyint. Eine Möglichkeit, um dieses Problem zu lösen, besteht darin, die Abfrage so zu ändern, dass die Konvertierung nur dann ausgeführt wird, wenn z ein Wert des Datentyps numeric ist, indem folgende CASE-Anweisung eingefügt wird:

SELECT CASE WHEN ISNUMERIC(z) = 1
    THEN CONVERT(tinyint, z) 
    ELSE 0 
END
FROM T INNER JOIN S ON x = a AND y > b
OPTION(HASH JOIN)

Eine zweite Lösung besteht darin, auf das Verwenden des speziellen Zeichenfolgenwerts 'unknown' in der Datenbank zu verzichten und stattdessen NULL zu verwenden. Eine dritte Lösung besteht darin, den Datentyp der z-Spalte in tinyint zu ändern und die Konvertierung vollständig zu vermeiden. Weil jedoch derartige Lösungen Änderungen an Daten bzw. an Schemas erfordern, sind sie möglicherweise mit einem größeren Aufwand verbunden als das Ändern der Abfrage. Allerdings können diese Lösungen trotzdem geeignet sein, wenn sie auch das Schreiben anderer Abfragen erleichtern.

Warnung bei NULL-Eingaben von Aggregatfunktionen

Aggregatfunktionen, wie z. B. MIN, geben eine Warnung aus, dass ein NULL-Wert entfernt wurde, wenn ihre Eingabe einen NULL-Wert enthält. Diese Warnung kann planabhängig sein. Wenn die NULL-Eingaben in die Aggregation nicht verarbeitet werden sollen, damit keine Warnung ausgegeben wird, können Sie Ihre Abfrage lokal ändern, um NULL-Werte zu entfernen. Berücksichtigen Sie die SELECT-Anweisung im folgenden Beispiel:

USE tempdb
GO
IF OBJECT_ID('newtitles','U') IS NOT NULL
....DROP TABLE newtitles 
GO
CREATE TABLE dbo.newtitles 
   (title varchar (80) NULL ,
    pubdate datetime NULL)
GO
INSERT dbo.newtitles VALUES('Title 1', NULL)
INSERT dbo.newtitles VALUES('Title 2', '20050311')
GO
SELECT t.title, t.pubdate, m.min_pubdate
FROM newtitles AS t,
   (SELECT MIN(pubdate) AS min_pubdate 
    FROM newtitles) AS m
WHERE t.pubdate = m.min_pubdate
GO

In SQL Server 2008 generiert diese Abfrage eine Warnung. Es wird keine Warnung erzeugt, wenn Sie die Abfrage durch Hinzufügen der Bedingung WHERE pubdate IS NOT NULL ändern, um die NULL-Werte vor der Aggregation auszufiltern.

SELECT t.title, t.pubdate, m.min_pubdate
FROM newtitles AS t,
   (SELECT MIN(pubdate) AS min_pubdate 
    FROM newtitles
    WHERE pubdate IS NOT NULL) AS m
WHERE t.pubdate = m.min_pubdate
GO

Siehe auch

Andere Ressourcen