Verwenden der INDEX- und FORCESEEK-Abfragehinweise in Planhinweislisten

Sie können INDEX- und FORCESEEK-Tabellenhinweise als Abfragehinweise angeben. Wenn diese Hinweise als Abfragehinweise angegeben werden, verhalten sie sich genauso wie eine Inlinetabelle oder ein Sichthinweis.

Der INDEX-Hinweis zwingt den Abfrageoptimierer, nur die angegebenen Indizes zu verwenden, um auf die Daten in der referenzierten Tabelle oder Sicht in der Abfrage zuzugreifen. Der FORCESEEK -Hinweis zwingt den Abfrageoptimierer, nur einen Indexsuchvorgang zu verwenden, um auf die Daten in der referenzierten Tabelle oder Sicht zuzugreifen. Diese Hinweise können in der OPTION-Klausel einer Planhinweisliste zum Anpassen der Optimierung einer Abfrage verwendet werden. Wenn eine Abfrage mit einer Planhinweisliste übereinstimmt, wird die in der Planhinweisliste angegebene OPTION-Klausel vor dem Kompilieren und Optimieren zur Abfrage hinzugefügt. Weitere Informationen zu Planhinweislisten finden Sie unter Grundlegendes zu Planhinweislisten.

VorsichtshinweisVorsicht

Bei falscher Verwendung von Abfragehinweisen in Planhinweislisten kann es zu Kompilierungs-, Ausführungs- oder Leistungsproblemen kommen. Daher sollten Planhinweislisten nur von erfahrenen Entwicklern und Datenbankadministratoren verwendet werden.

Wenn die INDEX- und FORCESEEK-Tabellenhinweise als Abfragehinweise angegeben werden, sind sie für die folgenden Objekte gültig:

  • Tabellen

  • Sichten

  • Indizierte Sichten

  • Allgemeine Tabellenausdrücke (Der Hinweis muss in der SELECT-Anweisung angegeben sein, mit deren Resultset der allgemeine Tabellenausdruck aufgefüllt wird.)

  • Dynamische Verwaltungssichten

  • Benannte Unterabfragen

Tabellenhinweise können nicht für Tabellenwertfunktionen, Tabellenvariablen oder OPENROWSET-Anweisungen angegeben werden.

Um einen Indexhinweis für eine indizierte Sicht anzugeben, muss der NOEXPAND-Hinweis auch in der OPTION-Klausel angegeben werden; andernfalls wird der Indexhinweis ignoriert. Weitere Informationen finden Sie unter Auflösen von Indizes für Sichten.

Informationen zur Syntax zum Angeben der INDEX- und FORCESEEK-Hinweise als Abfragehinweise finden Sie unter Abfragehinweise (Transact-SQL).

Bewährte Methoden

Wir empfehlen die folgenden bewährten Methoden:

  • Verwenden Sie die INDEX- und FORCESEEK-Hinweise nur im Kontext einer Planhinweisliste oder in Ad-hoc-Abfragen als Abfragehinweise, wenn Sie Planhinweislisten-Anweisungen testen. Geben Sie für alle anderen Ad-hoc-Abfragen diese Hinweise als Tabellenhinweise an.

  • Stellen Sie vor dem Verwenden des FORCESEEK-Hinweises sicher, dass die Statistiken in der Datenbank aktuell und korrekt sind.

    Mithilfe aktueller Statistiken kann der Abfrageoptimierer die Kosten verschiedener Abfragepläne genau abschätzen und einen hochwertigen Plan auswählen. Deshalb empfehlen wir, AUTO_CREATE_STATISTICS und AUTO_UPDATE_STATISTICS für jede Benutzerdatenbank auf ON (der Standard) festzulegen. Alternativ können Sie Statistiken in einer Tabelle oder Sicht mithilfe der UPDATE STATISTICS-Anweisung manuell aktualisieren.

  • Verwenden Sie den INDEX-Hinweis nicht unnötigerweise in Verbindung mit FORCESEEK. Das heißt, wenn durch FORCESEEK alleine ein geeigneter Plan erstellt wird, wird durch zusätzliche Verwendung des INDEX-Hinweises die Auswahl des Abfrageoptimierers übermäßig eingeschränkt. Außerdem wird durch einen INDEX-Hinweis in Ihrer Abfrage ein Fehler verursacht, wenn Sie das physische Schema Ihrer Tabelle ändern, um den in dem Hinweis angegebenen Index zu entfernen. Im Gegensatz dazu wird die Abfrage selbst dann kompiliert, wenn Sie Ihre Indexstrukturen ändern, solange mindestens ein verwendbarer Index in der Tabelle vorhanden ist, auf die der FORCESEEK-Hinweis angewendet wird.

  • Verwenden Sie den INDEX-Hinweis INDEX (0) nicht mit dem FORCESEEK-Hinweis. Durch INDEX (0) wird ein Scan der Basistabelle erzwungen. Bei Verwendung mit FORCESEEK wird kein Plan gefunden, und der Fehler 8622 wird zurückgegeben.

  • Verwenden Sie den USE PLAN-Abfragehinweis nicht mit dem FORCESEEK-Hinweis. Andernfalls wird der FORCESEEK-Hinweis ignoriert.

Verwenden der INDEX- und FORCESEEK-Hinweise mit anderen Tabellenhinweisen

Die INDEX- und FORCESEEK-Hinweise können für eine Abfrage angegeben werden, die nicht über vorhandene Tabellenhinweise verfügt, oder sie können verwendet werden, um einen oder mehrere vorhandene INDEX- oder FORCESEEK-Hinweise in der Abfrage zu ersetzen. Wenn eine mit einer Planhinweisliste übereinstimmende Abfrage bereits eine WITH-Klausel besitzt, die diese Tabellenhinweise angibt, ersetzen die im @hints-Parameter angegebenen Hinweise der Planhinweisliste die in der Abfrage enthaltenen Hinweise. Wenn die Abfrage beispielsweise den Tabellenhinweis WITH INDEX (PK_Employee_EmployeeID) für die HumanResources.Employee-Tabelle enthält und der @hints-Parameter in der Planhinweisliste OPTION (TABLE HINT ( HumanResources.Employee, INDEX( IX_Employee_ManagerID ) ) angibt, verwendet der Abfrageoptimierer den IX_Employee_ManagerID-Index.

Andere Tabellenhinweise als INDEX und FORCESEEK sind als Abfragehinweise in der Planhinweisliste nicht zulässig, es sei denn, die Abfrage enthält bereits eine WITH-Klausel, die einen Tabellenhinweis angibt. In diesem Fall muss, um die Semantik der Abfrage beizubehalten, mithilfe von TABLE HINT in der OPTION-Klausel auch ein übereinstimmender Hinweis als Abfragehinweis angegeben werden. Wenn die Abfrage beispielsweise den Tabellenhinweis NOLOCK enthält, muss der @hints-Parameter der Planhinweisliste neben den INDEX- oder FORCESEEK-Tabellenhinweisen in der OPTION-Klausel ebenfalls den NOLOCK-Hinweis enthalten. Informationen finden Sie unter Beispiel C weiter unten in diesem Thema. Wenn ein anderer Tabellenhinweis als INDEX oder FORCESEEK mithilfe von TABLE HINT in der OPTION-Klausel ohne übereinstimmenden Abfragehinweis angegeben wurde (oder umgekehrt), wird als Hinweis darauf, dass die OPTION-Klausel eine Änderung der Semantik der Abfrage bewirken kann, der Fehler 8702 ausgelöst, und die Abfrage schlägt fehl.

Verwenden der INDEX- und FORCESEEK-Hinweise mit anderen Abfragehinweisen

Wenn eine mit einer Planhinweisliste übereinstimmende Abfrage bereits eine OPTION-Klausel besitzt, die Abfragehinweise angibt, ersetzen die im @hints-Parameter angegebenen Abfragehinweise der Planhinweisliste die in der Abfrage enthaltenen Hinweise. Damit eine Planhinweisliste jedoch mit einer Abfrage übereinstimmt, die bereits eine OPTION-Klausel besitzt, müssen Sie die OPTION-Klausel der Abfrage aufnehmen, wenn Sie den Text der Abfrage angeben, der mit der sp_create_plan_guide (Transact-SQL)-Anweisung übereinstimmen soll. Wenn Sie möchten, dass die in der Planhinweisliste angegebenen Abfragehinweise zu den bereits in der Abfrage vorhandenen Hinweisen hinzugefügt werden, statt diese zu ersetzen, müssen Sie in der OPTION-Klausel der Planhinweisliste sowohl die ursprünglichen Hinweise als auch die zusätzlichen Hinweise angeben.

Beispiele

A. Verwenden des FORCESEEK-Hinweises

Im folgenden Beispiel wird der FORCESEEK-Hinweis im @hints-Parameter der Planhinweisliste verwendet. Diese Option zwingt den Abfrageoptimierer, einen Indexsuchvorgang zu verwenden, um auf die Daten in der HumanResources.Employee-Tabelle oder -Sicht zuzugreifen. Beachten Sie, dass der Abfrageoptimierer dadurch möglicherweise gezwungen wird, einen anderen Index als den in dem Tabellenhinweis angegebenen zu verwenden.

USE AdventureWorks;
GO
EXEC sp_create_plan_guide 
    @name = N'Guide3', 
    @stmt = N'SELECT c.LastName, c.FirstName, HumanResources.Employee.Title
              FROM HumanResources.Employee
              JOIN Person.Contact AS c ON HumanResources.Employee.ContactID = c.ContactID
              WHERE HumanResources.Employee.ManagerID = 3
              ORDER BY c.LastName, c.FirstName;', 
    @type = N'SQL',
    @module_or_batch = NULL, 
    @params = NULL, 
    @hints = N'OPTION (TABLE HINT( HumanResources.Employee, FORCESEEK))';
GO

B. Verwenden von mehreren Tabellenhinweisen

Im folgenden Beispiel wird der INDEX-Hinweis auf eine Tabelle angewendet, und der FORCESEEK-Hinweis wird auf eine andere Tabelle angewendet.

USE AdventureWorks;
GO
EXEC sp_create_plan_guide 
    @name = N'Guide4', 
    @stmt = N'SELECT e.ManagerID, c.LastName, c.FirstName, e.Title
              FROM HumanResources.Employee AS e 
              JOIN Person.Contact AS c ON e.ContactID = c.ContactID
              WHERE e.ManagerID = 3;', 
    @type = N'SQL',
    @module_or_batch = NULL, 
    @params = NULL, 
    @hints = N'OPTION (TABLE HINT ( e, INDEX( IX_Employee_ManagerID ) ) 
                       , TABLE HINT ( c, FORCESEEK) )';
GO

C. Angeben von Semantik-beeinflussenden Hinweisen

Das folgende Beispiel enthält zwei Tabellenhinweise in der Abfrage: den NOLOCK-Hinweis, der semantisch beeinflussend ist, und den INDEX-Hinweis, der nicht semantisch beeinflussend ist. Der NOLOCK-Hinweis wird in der OPTIONS-Klausel der Planhinweisliste angegeben, um die Semantik der Abfrage zu bewahren. Abgesehen von dem NOLOCK-Hinweis werden auch der INDEX- und der FORCESEEK-Hinweis angegeben, die den die Semantik nicht beeinflussenden INDEX-Hinweis in der Abfrage ersetzen, wenn die Anweisung kompiliert und optimiert wird.

USE AdventureWorks;
GO
EXEC sp_create_plan_guide 
    @name = N'Guide6', 
    @stmt = N'SELECT c.LastName, c.FirstName, e.Title
              FROM HumanResources.Employee AS e 
                   WITH (NOLOCK, INDEX (PK_Employee_EmployeeID))
              JOIN Person.Contact AS c ON e.ContactID = c.ContactID
              WHERE e.ManagerID = 3;',
    @type = N'SQL',
    @module_or_batch = NULL, 
    @params = NULL, 
    @hints = N'OPTION (TABLE HINT ( e, INDEX( IX_Employee_ManagerID) , NOLOCK, FORCESEEK ))';
GO

Das folgende Beispiel zeigt eine alternative Methode, um die Semantik der Abfrage zu bewahren und zu ermöglichen, dass der Abfrageoptimierer einen anderen als den in dem Tabellenhinweis angegebenen Index verwendet. Dies erfolgt durch Angabe des NOLOCK-Hinweises in der OPTIONS-Klausel (da dieser die Semantik beeinflusst) und durch Angabe des TABLE HINT-Schlüsselworts nur mit einem Tabellenverweis und ohne INDEX-Hinweis.

USE AdventureWorks;
GO
EXEC sp_create_plan_guide 
    @name = N'Guide7', 
    @stmt = N'SELECT c.LastName, c.FirstName, e.Title
              FROM HumanResources.Employee AS e 
                   WITH (NOLOCK, INDEX (PK_Employee_EmployeeID))
              JOIN Person.Contact AS c ON e.ContactID = c.ContactID
              WHERE e.ManagerID = 2;',
    @type = N'SQL',
    @module_or_batch = NULL, 
    @params = NULL, 
    @hints = N'OPTION (TABLE HINT ( e, NOLOCK))';
GO

D. Verwenden von TABLE HINT, um einen vorhandenen Tabellenhinweis zu überschreiben

Das folgende Beispiel zeigt, wie TABLE HINT ohne Angabe eines INDEX-Hinweises verwendet wird, um das Verhalten des INDEX-Tabellenhinweises zu überschreiben, der in der FROM-Klausel der Abfrage angegeben ist. Bei dieser Methode kann der Abfrageoptimierer einen anderen als den in dem Tabellenhinweis angegebenen Index auswählen.

USE AdventureWorks;
GO
EXEC sp_create_plan_guide 
    @name = N'Guide5', 
    @stmt = N'SELECT e.ManagerID, c.LastName, c.FirstName, e.Title
              FROM HumanResources.Employee AS e WITH (INDEX (IX_Employee_ManagerID))
              JOIN Person.Contact AS c ON e.ContactID = c.ContactID
              WHERE e.ManagerID = 3;', 
    @type = N'SQL',
    @module_or_batch = NULL, 
    @params = NULL, 
    @hints = N'OPTION (TABLE HINT(e))';
GO