Inlining benutzerdefinierter Skalarfunktionen

Gilt für: SQL Server 2019 (15.x) Azure SQL-Datenbank Azure SQL-verwaltete Instanz

Dieser Artikel stellt eine Einführung in das Inlining benutzerdefinierter Skalarfunktionen dar. Dabei handelt es sich um ein Feature für die intelligente Abfrageverarbeitung. Dieses Feature verbessert die Leistung von Abfragen, die skalare UDFs in SQL Server aufrufen (beginnend mit SQL Server 2019 (15.x)).

Benutzerdefinierte T-SQL-Skalarfunktionen

Benutzerdefinierte Funktionen (User-Defined Functions, UDFs), die in Transact-SQL implementiert sind und einen einzelnen Datenwert zurückgeben, werden als T-SQL Scalar User-Defined Functions bezeichnet. T-SQL UDFs sind eine elegante Möglichkeit, Codewiederverwendung und Modularität in Transact-SQL-Abfragen zu erreichen. Einige Berechnungen (z.B. komplexe Geschäftsregeln) können einfacher in imperativer UDF-Form ausgedrückt werden. Mit benutzerdefinierten Funktionen können Sie eine komplexe Logik erstellen, ohne komplexe SQL-Abfragen schreiben zu können. Weitere Informationen zu benutzerdefinierten Funktionen (UDFs) finden Sie unter Erstellen von benutzerdefinierten Funktionen (Datenbank-Engine).

Leistung von benutzerdefinierten Skalarfunktionen

Die Leistung von benutzerdefinierten Skalarfunktionen ist aus folgenden Gründen häufig niedrig:

  • Iterative Aufrufe. Benutzerdefinierte Funktionen werden einmal pro qualifiziertem Tupel iterativ aufgerufen. Durch diese Funktionsaufrufe entstehen zusätzliche Kosten für den Kontextwechsel. Insbesondere udFs, die Transact-SQL-Abfragen in ihrer Definition ausführen, sind stark betroffen.

  • Mangel an Kosten. Während der Optimierung werden nur relationale Operatoren kosten, während skalare Operatoren nicht. Vor der Einführung von skalaren UDFs waren andere Skalaroperatoren im Allgemeinen billig und erforderten keine Kosten. Es war ausreichend, geringe CPU-Kosten für einen Skalarvorgang hinzuzufügen. In einigen Szenarios sind die tatsächlichen Kosten jedoch wichtig und werden dennoch nicht ausreichend repräsentiert.

  • Interpretierte Ausführung. Benutzerdefinierte Funktionen werden als Anweisungsbatch ausgewertet und Anweisung für Anweisung ausgeführt. Jede Anweisung wird kompiliert, und der kompilierte Plan wird zwischengespeichert. Die Zwischenspeicherung spart zwar Zeit, da Neukompilierungen vermieden werden, aber jede Anweisung wird isoliert ausgeführt. Es können keine anweisungsübergreifenden Optimierungen durchgeführt werden.

  • Serielle Ausführung. SQL Server lässt in Abfragen, die UDFs aufrufen, keine Intraabfrage-Parallelität zu.

Automatisches Inlining von benutzerdefinierrten Skalarfunktionen

Das Ziel des Scalar UDF Inlining-Features besteht darin, die Leistung von Abfragen zu verbessern, die T-SQL-skalare UDFs aufrufen, wobei die UDF-Ausführung der Standard Engpass ist.

Mit diesem neuen Feature werden benutzerdefinierte Skalarfunktionen automatisch in Skalarausdrücke oder skalare Unterabfragen transformiert, die in der aufrufenden Abfrage den UDF-Operator ersetzen. Diese Ausdrücke und Unterabfragen werden anschließend optimiert. Dadurch enthält der Abfrageplan keinen UDF-Operator mehr. Seine Auswirkungen werden im Plan überwacht, z.B. Ansichten oder Inline-Tabellenwertfunktionen.

Beispiel 1 : Einzelne Anweisung skalare UDF

Sehen Sie sich die folgende Abfrage an:

SELECT L_SHIPDATE, O_SHIPPRIORITY, SUM (L_EXTENDEDPRICE *(1 - L_DISCOUNT))
FROM LINEITEM
INNER JOIN ORDERS
  ON O_ORDERKEY = L_ORDERKEY
GROUP BY L_SHIPDATE, O_SHIPPRIORITY ORDER BY L_SHIPDATE;

Diese Abfrage berechnet die Summe der reduzierten Preise für Einzelposten und gruppiert die Ergebnisse nach Versanddatum und Versandpriorität. Der Ausdruck L_EXTENDEDPRICE *(1 - L_DISCOUNT) enthält die Formel für den reduzierten Preis eines bestimmten Einzelpostens. Solche Formeln können in Funktionen extrahiert werden, um Modularität und Wiederverwendbarkeit zu erreichen.

CREATE FUNCTION dbo.discount_price(@price DECIMAL(12,2), @discount DECIMAL(12,2))
RETURNS DECIMAL (12,2) AS
BEGIN
  RETURN @price * (1 - @discount);
END

Die Abfrage kann nun geändert werden, um diese benutzerdefinierte Funktion aufzurufen.

SELECT L_SHIPDATE, O_SHIPPRIORITY, SUM (dbo.discount_price(L_EXTENDEDPRICE, L_DISCOUNT))
FROM LINEITEM
INNER JOIN ORDERS
  ON O_ORDERKEY = L_ORDERKEY
GROUP BY L_SHIPDATE, O_SHIPPRIORITY ORDER BY L_SHIPDATE

Wie zuvor beschrieben ist die Leistung der Abfrage mit der benutzerdefinierten Funktion niedrig. Mit Scalar UDF Inlining wird nun der skalare Ausdruck im Textkörper der UDF direkt in der Abfrage ersetzt. Die Ergebnisse dieser Abfrage werden in folgender Tabelle aufgeführt:

Abfrage: Abfrage ohne benutzerdefinierte Funktion Abfrage mit benutzerdefinierter Funktion (ohne Inlining) Abfrage mit skalarer UDF-Inlining
Ausführungszeit: 1,6 Sekunden 29 Minuten, 11 Sekunden 1,6 Sekunden

Diese Zahlen basieren auf einer CCI-Datenbank mit 10 GB (mit dem TPC-H-Schema), die auf einem Computer mit Dualprozessor (12 Kerne), 96 GB RAM und SSD-Sicherung ausgeführt wird. Dabei wurden die Kompilier- und die Ausführungszeit mit einem kalten Prozedurcache und Pufferpool eingeschlossen. Die Standardkonfiguration wurde verwendet, und es wurden keine weiteren Indizes erstellt.

Beispiel 2 : Skalarer UDF mit mehreren Anweisungen

Für benutzerdefinierte Skalarfunktionen, die über mehrere T-SQL-Anweisungen implementiert werden, z.B. Variablenzuweisungen und bedingte Verzweigungen, kann ebenfalls ein Inlining durchgeführt werden. Sehen Sie sich folgende benutzerdefinierte Skalarfunktion an, die die Servicekategorie für einen bestimmten Kunden bestimmt, wenn ein benutzerdefinierter Schlüssel vorhanden ist. Die Kategorie wird erreicht, indem zuerst der Gesamtpreis aller Bestellungen des Kunden mithilfe einer SQL-Abfrage berechnet wird. Anschließend wird eine IF (...) ELSE-Logik verwendet, um die Kategorie auf Grundlage des Gesamtpreises zu bestimmen.

CREATE OR ALTER FUNCTION dbo.customer_category(@ckey INT)
RETURNS CHAR(10) AS
BEGIN
  DECLARE @total_price DECIMAL(18,2);
  DECLARE @category CHAR(10);

  SELECT @total_price = SUM(O_TOTALPRICE) FROM ORDERS WHERE O_CUSTKEY = @ckey;

  IF @total_price < 500000
    SET @category = 'REGULAR';
  ELSE IF @total_price < 1000000
    SET @category = 'GOLD';
  ELSE
    SET @category = 'PLATINUM';

  RETURN @category;
END

Sehen Sie sich nun eine Abfrage an, die diese benutzerdefinierte Funktion aufruft.

SELECT C_NAME, dbo.customer_category(C_CUSTKEY) FROM CUSTOMER;

Der Ausführungsplan für diese Abfrage in SQL Server 2017 (14.x) (Kompatibilitätsebene 140 und früher) lautet wie folgt:

Query Plan without inlining.

Der Plan zeigt, dass SQL Server in diesem Fall eine einfache Strategie übernimmt: Für jedes Tupel in der CUSTOMER-Tabelle werden die benutzerdefinierte Funktion aufgerufen und die Ergebnisse ausgegeben. Diese Strategie ist jedoch zu einfach und nicht effizient. Durch Inlining werden solche benutzerdefinierten Funktionen in gleichwertige skalare Unterabfragen transformiert, die die benutzerdefinierte Funktion in der aufrufenden Abfrage ersetzen.

Der Plan mit Inlining der benutzerdefinierten Funktion sieht für die gleiche Abfrage folgendermaßen aus.

Query Plan with inlining.

Wie zuvor erwähnt enthält der Abfrageplan keinen UDF-Operator mehr. Seine Auswirkungen sind nun im Plan ersichtlich, z.B. Ansichten oder Inline-Tabellenwertfunktionen. Hier sind die wichtigsten Beobachtungen, die aus dem obigen Plan resultieren:

  • SQL Server hat den impliziten Join zwischen CUSTOMER und ORDERS abgeleitet und diesen über einen Joinoperator in einen expliziten transformiert.
  • SQL Server hat außerdem die implizite GROUP BY O_CUSTKEY on ORDERS-Anweisung abgeleitet und „IndexSpool + StreamAggregate“ verwendet, um diese zu implementieren.
  • SQL Server verwendet nun einen Parallelismus für alle Operatoren.

Je nach Komplexität der Logik in der benutzerdefinierten Funktion kann der resultierende Abfrageplan größer und komplexer werden. Wie wir sehen können, sind die Vorgänge innerhalb der UDF jetzt nicht mehr undurchsichtig, sodass der Abfrageoptimierer diese Vorgänge kosten und optimieren kann. Da die benutzerdefinierte Funktion sich nicht mehr im Plan befindet, wird der iterative Aufruf derselben durch einen Plan ersetzt, der den Aufwand, der durch Funktionsaufrufe entsteht, vollständig vermeidet.

Inlineable skalare UDF-Anforderungen

Eine skalare T-SQL-UDF kann inlineiert werden, wenn alle folgenden Bedingungen erfüllt sind:

  • Die UDF wird mit den folgenden Konstrukten geschrieben:
    • DECLARE, SET: Variablendeklaration und -zuweisungen
    • SELECT: SQL-Abfrage mit einzel/mehreren Variablenzuweisungen 1.
    • IF/ELSE: Verzweigung mit beliebigen Schachtelungsebenen
    • RETURN: eine oder mehrere RETURN-Anweisungen Ab SQL Server 2019 (15.x) CU5 kann die UDF nur eine einzelne RETURN-Anweisung enthalten, die für die Inlineierung 6 berücksichtigt werden soll.
    • UDF: Geschachtelte/rekursive Funktion ruft 2 auf.
    • Sonstige: relationale Operatoren wie EXISTS, IS NULL
  • Die UDF ruft keine systeminterne Funktion auf, die entweder zeitabhängig ist (z GETDATE(). B. ) oder nebenwirkungen 3 hat (z NEWSEQUENTIALID(). B. ).
  • Die UDF verwendet die EXECUTE AS CALLER Klausel (Standardverhalten, wenn die EXECUTE AS Klausel nicht angegeben ist).
  • Die UDF verweist nicht auf Tabellenvariablen oder Tabellenwertparameter.
  • Die Abfrage, die eine skalare UDF aufruft, verweist nicht auf einen skalaren UDF-Aufruf in seiner GROUP BY Klausel.
  • Die Abfrage, die eine skalare UDF in der Auswahlliste mit DISTINCT Klausel aufruft, enthält ORDER BY keine Klausel.
  • Die UDF wird nicht in ORDER BY Klauseln verwendet.
  • Die UDF wird nicht nativ kompiliert (Interop wird unterstützt).
  • Die UDF wird nicht in einer berechneten Spalte oder einer Check-Einschränkungsdefinition verwendet.
  • Die UDF verweist nicht auf benutzerdefinierte Typen.
  • Zur benutzerdefinierten Funktion werden keine Signaturen hinzugefügt.
  • Die UDF ist keine Partitionsfunktion.
  • Die UDF enthält keine Verweise auf allgemeine Tabellenausdrücke (COMMON Table Expressions, CTEs).
  • Die UDF enthält keine Verweise auf systeminterne Funktionen, die die Ergebnisse ändern können, wenn sie inlined (z @@ROWCOUNT. B. ) 4 sind.
  • Die UDF enthält keine Aggregatfunktionen, die als Parameter an eine skalare UDF 4 übergeben werden.
  • Die UDF verweist nicht auf integrierte Ansichten (z OBJECT_ID. B. ) 4.
  • Die UDF verweist nicht auf XML-Methoden 5.
  • Die UDF enthält keine SELECT ohne ORDER BYTOP 1 Klausel 5.
  • Die UDF enthält keine SELECT-Abfrage, die eine Zuordnung mit der ORDER BY Klausel (z SELECT @x = @x + 1 FROM table1 ORDER BY col1. B. ) 5 ausführt.
  • Die UDF enthält nicht mehrere RETURN-Anweisungen 6.
  • Die UDF wird nicht aus einer RETURN-Anweisung 6 aufgerufen.
  • Die UDF verweist nicht auf die STRING_AGG Funktion 6.
  • Die UDF verweist nicht auf Remotetabellen 7.
  • Die UDF-aufrufende Abfrage verwendet GROUPING SETSweder nochCUBEROLLUP 7.
  • Die UDF-aufrufende Abfrage enthält keine Variable, die als UDF-Parameter für die Zuordnung (zSELECT @y = 2. B. , ) @x = UDF(@y)7 verwendet wird.
  • Die UDF verweist nicht auf verschlüsselte Spalten 8.
  • Die UDF enthält keine Verweise auf WITH XMLNAMESPACES8.
  • Die Abfrage, die die UDF aufruft, enthält keine allgemeinen Tabellenausdrücke (COMMON Table Expressions, CTEs) 8.

1SELECT mit variabler Akkumulation/Aggregation wird für die Inlinierung (z SELECT @val += col1 FROM table1. B. ) nicht unterstützt.

2 Für rekursive benutzerdefinierte Funktionen wird das Inlining nur bis zu einem bestimmten Grad durchgeführt.

3 Intrinsische Funktionen, deren Ergebnisse von der aktuellen Systemzeit abhängen, sind zeitabhängig. Ein Beispiel für eine Funktion mit Nebeneffekten ist eine intrinsische Funktion, die einen internen globalen Status aktualisieren kann. Diese Funktionen geben jedes Mal unterschiedliche Ergebnisse zurück, wenn sie aufgerufen werden, basierend auf dem internen Zustand.

4 Einschränkung hinzugefügt in SQL Server 2019 (15.x) CU2

5 Einschränkung hinzugefügt in SQL Server 2019 (15.x) CU4

6 Einschränkung hinzugefügt in SQL Server 2019 (15.x) CU5

7 Einschränkung hinzugefügt in SQL Server 2019 (15.x) CU6

8 Einschränkung hinzugefügt in SQL Server 2019 (15.x) CU11

Informationen zu den neuesten T-SQL Scalar UDF Inlining Fixes und Änderungen zur Inlineierung von Berechtigungsszenarien finden Sie im Knowledge Base-Artikel: FIX: Scalar UDF Inlining-Probleme in SQL Server 2019.

Überprüfen, ob eine UDF inlined sein kann

Für jede benutzerdefinierte T-SQL-Skalarfunktion enthält die Katalogansicht sys.sql_modules eine Eigenschaft namens is_inlineable, die angibt, ob für eine benutzerdefinierte Funktion ein Inlining möglich ist.

Die is_inlineable-Eigenschaft wird von den Konstrukten abgeleitet, die in der Definition der benutzerdefinierten Skalarfunktion gefunden werden. Es wird nicht überprüft, ob die UDF zur Kompilierungszeit inlineierbar ist. Weitere Informationen finden Sie im Abschnitt zu den Bedingungen für Inlining.

Der Wert 1 gibt an, dass ein Inlining möglich ist, während der Wert 0 angibt, dass kein Inlining möglich ist. Diese Eigenschaft enthält für alle Inline-Tabellenwertfunktionen den Wert 1. Für alle anderen Module ist der Wert 0.

Wenn eine skalare UDF inlineierbar ist, bedeutet dies nicht, dass sie immer inlineiert wird. SQL Server entscheidet (pro Abfrage und pro benutzerdefinierter Funktion), ob für eine benutzerdefinierte Funktion ein Inlining durchgeführt wird. Einige Beispiele, in denen für eine benutzerdefinierte Funktion möglicherweise kein Inlining durchgeführt werden kann, finden Sie im Folgenden:

  • Wenn die UDF-Definition tausende Codezeilen enthält, kann SQL Server es möglicherweise nicht inlineieren.

  • Ein UDF-Aufruf in einer GROUP BY Klausel wird nicht inlineiert. Diese Entscheidung erfolgt, wenn die Abfrage, die auf eine benutzerdefinierte Skalarfunktion verweist, kompiliert wird.

  • Die benutzerdefinierte Funktion ist mit einem Zertifikat signiert. Da Signaturen nach dem Erstellen einer UDF hinzugefügt und gelöscht werden konnten, entscheidet sich, ob sie inline ist oder nicht, wenn die Abfrage, die auf eine skalare UDF verweist, kompiliert wird. Systemfunktionen sind z. B. in der Regel mit einem Zertifikat signiert. Sie können sys.crypt_properties verwenden, um zu ermitteln, welche Objekte signiert sind.

    SELECT *
    FROM sys.crypt_properties AS cp
    INNER JOIN sys.objects AS o ON cp.major_id = o.object_id;
    

Überprüfen, ob die Inlinierung stattgefunden hat oder nicht

Wenn alle Bedingungen erfüllt sind und SQL Server ein Inlining durchführt, wird die benutzerdefinierte Funktion in einen relationalen Ausdruck transformiert. Anhand des Abfrageplans können Sie ganz einfach herausfinden, ob die Inlineierung stattgefunden hat oder nicht:

  • Die Plan-XML verfügt nicht über einen <UserDefinedFunction> XML-Knoten für eine UDF, die erfolgreich inlineiert wurde.
  • Bestimmte erweiterte Events (XEvents) werden ausgegeben.

Aktivieren der Skalar-UDF-Inlining

Sie können Workloads automatisch für das Inlining benutzerdefinierter Skalarfunktionen zulassen, indem Sie den Kompatibilitätsgrad 150 für die Datenbank aktivieren. Diesen können Sie mit Transact-SQL festlegen. Beispiel:

ALTER DATABASE [WideWorldImportersDW] SET COMPATIBILITY_LEVEL = 150;

Es müssen keine weiteren Änderungen vorgenommen, damit dieses Feature für benutzerdefinierte Funktionen oder Abfragen verwendet werden kann.

Deaktivieren der Skalar-UDF-Inlining ohne Ändern der Kompatibilitätsstufe

Skalare UDF-Inlining können auf Datenbank-, Anweisungs- oder UDF-Bereich deaktiviert werden, während sie weiterhin die Kompatibilitätsebene 150 und höher der Datenbank Standard. Um skalare UDF-Inlining im Datenbankbereich zu deaktivieren, führen Sie die folgende Anweisung im Kontext der entsprechenden Datenbank aus:

ALTER DATABASE SCOPED CONFIGURATION SET TSQL_SCALAR_UDF_INLINING = OFF;

Führen Sie folgende Anweisung im Kontext einer Datenbank aus, um das Inlining für benutzerdefinierte Skalarfunktionen für eine Datenbank wieder zu aktivieren:

ALTER DATABASE SCOPED CONFIGURATION SET TSQL_SCALAR_UDF_INLINING = ON;

Wenn die Option auf ON festgelegt ist, wird die Einstellung in sys.database_scoped_configurations als „aktiviert“ angezeigt. Sie können das Inlining benutzerdefinierter Skalarfunktionen für eine bestimmte Abfrage auch deaktivieren, indem Sie DISABLE_TSQL_SCALAR_UDF_INLINING als USE HINT-Abfragehinweis festlegen.

Ein USE HINT-Abfragehinweis hat Vorrang vor einer datenbankweit gültigen Konfiguration oder einer Einstellung des Kompatibilitätsgrads.

Beispiel:

SELECT L_SHIPDATE, O_SHIPPRIORITY, SUM (dbo.discount_price(L_EXTENDEDPRICE, L_DISCOUNT))
FROM LINEITEM
INNER JOIN ORDERS
  ON O_ORDERKEY = L_ORDERKEY
GROUP BY L_SHIPDATE, O_SHIPPRIORITY ORDER BY L_SHIPDATE
OPTION (USE HINT('DISABLE_TSQL_SCALAR_UDF_INLINING'));

Das Inlining benutzerdefinierter Skalarfunktionen kann auch für eine bestimmte benutzerdefinierte Funktion deaktiviert werden, indem Sie die INLINE-Klausel in der CREATE FUNCTION- oder ALTER FUNCTION-Anweisung verwenden. Beispiel:

CREATE OR ALTER FUNCTION dbo.discount_price(@price DECIMAL(12,2), @discount DECIMAL(12,2))
RETURNS DECIMAL (12,2)
WITH INLINE = OFF
AS
BEGIN
    RETURN @price * (1 - @discount);
END;

Sobald die oben genannte Anweisung ausgeführt wurde, wird für diese benutzerdefinierte Funktion kein Inlining durchgeführt, wenn sie von einer Abfrage aufgerufen wird. Führen Sie folgende Anweisung aus, um das Inlining für diese benutzerdefinierte Funktion wieder zu aktivieren:

CREATE OR ALTER FUNCTION dbo.discount_price(@price DECIMAL(12,2), @discount DECIMAL(12,2))
RETURNS DECIMAL (12,2)
WITH INLINE = ON
AS
BEGIN
    RETURN @price * (1 - @discount);
END

Die INLINE Klausel ist nicht obligatorisch. Wenn INLINE keine Klausel angegeben ist, wird sie automatisch basierend darauf festgelegt ON/OFF , ob die UDF inlined sein kann. Wenn INLINE = ON festgelegt ist, aber für die benutzerdefinierte Funktion kein Inlining durchgeführt werden kann, wird ein Fehler ausgegeben.

Wichtige Hinweise

Wie in diesem Artikel beschrieben, transformiert Scalar UDF Inlining eine Abfrage mit skalaren UDFs in eine Abfrage mit einer entsprechenden skalaren Unterabfrage. Durch diese Transformation kann es in folgenden Szenarios zu Unterschieden bei der Verhaltensweise kommen:

  1. Das Inlining führt zu einem anderen Abfragehash für den gleichen Abfragetext.

  2. Bestimmte Warnungen in Anweisungen in der benutzerdefinierten Funktion (z.B. die Division durch 0), die zuvor ausgeblendet waren, werden durch das Inlining nun möglicherweise angezeigt.

  3. Joinhinweise auf Abfrageebene sind möglicherweise nicht mehr gültig, da durch das Inlining neue Joins hinzugefügt werden. Sie müssen stattdessen lokale Joinhinweise verwenden.

  4. Ansichten, die auf inline skalare UDFs verweisen, können nicht indiziert werden. Wenn Sie einen Index in einer entsprechenden Ansicht erstellen müssen, sollten Sie das Inlining für die benutzerdefinierten Funktionen deaktivieren, auf die verwiesen wird.

  5. Durch das Inlining benutzerdefinierter Funktionen kann das Verhalten der dynamischen Datenmaskierung sich ändern.

    In bestimmten Situationen (abhängig von der Logik in der UDF) kann die Inlinierung im Hinblick auf das Maskieren von Ausgabespalten konservativer sein. In Szenarien, in denen die Spalten, auf die in einer UDF verwiesen wird, keine Ausgabespalten sind, werden sie nicht maskiert.

  6. Wenn eine benutzerdefinierte Funktion auf integrierte Funktionen wie SCOPE_IDENTITY(), @@ROWCOUNT oder @@ERROR verweist, ändert sich der Wert, der von der integrierten Funktion zurückgegeben wird, durch das Inlining. Diese Änderung im Verhalten geht darauf zurück, dass das Inlining den Bereich der Anweisungen in der benutzerdefinierten Funktion ändert. Ab SQL Server 2019 (15.x) CU2 wird die Inlinierung blockiert, wenn die UDF auf bestimmte systeminterne Funktionen verweist (z. B @@ROWCOUNT. ).

  7. Wenn eine Variable mit dem Ergebnis einer inlineierten UDF zugewiesen wird und sie auch als index_column_name in FORCESEEK-Abfragehinweis verwendet wird, führt dies zu einem Fehler Msg 8622, der angibt, dass der Abfrageprozessor aufgrund der in der Abfrage definierten Hinweise keinen Abfrageplan erstellen konnte.

Siehe auch