Verwenden des FORCESEEK-Tabellenhinweises

Der FORCESEEK-Tabellenhinweis zwingt den Abfrageoptimierer, nur einen Indexsuchvorgang als Zugriffspfad auf die in der Tabelle oder Sicht angegebenen Daten zu verwenden, auf die in der Abfrage verwiesen wurde. Sie können diesen Tabellenhinweis zum Außerkraftsetzen des vom Abfrageoptimierers ausgewählten Standardplans verwenden, um durch einen nicht effizienten Abfrageplan verursachte Leistungsprobleme zu vermeiden. Wenn ein Plan beispielsweise Tabellen- oder Indexscanoperatoren enthält und die entsprechenden Tabellen eine große Anzahl von Lesevorgängen beim Ausführen der Abfrage verursachen, wie in der STATISTICS IO-Ausgabe beobachtet, kann durch das Erzwingen eines Indexsuchvorgangs eine bessere Abfrageleistung erzielt werden. Dies gilt besonders, wenn ungenaue Kardinalitäts- oder Kostenschätzungen verursachen, dass der Optimierer Scanvorgänge zur Plankompilierungszeit bevorzugt.

FORCESEEK gilt sowohl für gruppierte als auch für nicht gruppierte Indexsuchvorgänge. Es kann für jede Tabelle oder Sicht in der FROM-Klausel einer SELECT-Anweisung und in der FROM<table_source>-Klausel einer UPDATE- oder DELETE-Anweisung angegeben werden.

VorsichtshinweisVorsicht

Da der SQL Server-Abfrageoptimierer in der Regel den optimalen Ausführungsplan für eine Abfrage auswählt, wird empfohlen, dass nur erfahrene Entwickler und Datenbankadministratoren Hinweise verwenden, wenn alle anderen Möglichkeiten sich als unbefriedigend erwiesen haben.

Auswerten von Abfrageplänen für die FORCESEEK-Anwendbarkeit

Der FORCESEEK-Tabellenhinweis kann nützlich sein, wenn der Abfrageplan einen Tabellen- oder Indexscanoperator in einer Tabelle oder Sicht verwendet, ein Indexoperator ist jedoch möglicherweise effizienter. Betrachten Sie die folgende Abfrage und den nachfolgenden Ausführungsplan.

USE AdventureWorks2008R2;
GO
SELECT *
FROM Sales.SalesOrderHeader AS h
INNER JOIN Sales.SalesOrderDetail AS d 
    ON h.SalesOrderID = d.SalesOrderID 
WHERE h.TotalDue > 100
AND (d.OrderQty > 5 OR d.LineTotal < 1000.00);
GO

Der folgende Ausführungsplan zeigt, dass der Abfrageoptimierer den Clustered Index Seek-Operator zum Zugriff auf die Daten in beiden Tabellen verwendet.

Ausführungsplan mit Clustered Index Scan-Operatoren

Sie können erzwingen, dass der Abfrageoptimierer einen Suchvorgang in der Sales.SalesOrderDetail-Tabelle durchführt, indem Sie den FORCESEEK-Hinweis wie in der folgenden Abfrage dargestellt festlegen.

USE AdventureWorks2008R2;
GO
SELECT *
FROM Sales.SalesOrderHeader AS h
INNER JOIN Sales.SalesOrderDetail AS d WITH (FORCESEEK)
    ON h.SalesOrderID = d.SalesOrderID 
WHERE h.TotalDue > 100
AND (d.OrderQty > 5 OR d.LineTotal < 1000.00);
GO

Der folgende Ausführungsplan zeigt die Ergebnisse der Verwendung des FORCESEEK-Hinweises in der Abfrage. Ein gruppierter Indexsuchvorgang wird zum Zugreifen auf die Daten in der Sales.SalesOrderDetail-Tabelle verwendet.

Ausführungsplan mit Clustered Index Seek-Operator

Indexvereinigung und Schnittmengenunterstützung

Der FORCESEEK-Hinweis unterstützt Indexvereinigungen und Schnittmengen. Durch den Hinweis wird es für den Abfrageoptimierer wahrscheinlicher, diese Techniken zu verwenden. Um das Verlangsamen der Kompilierungszeit einfacher Abfragen zu vermeiden, werden Indexvereinigungen und Schnittmengen üblicherweise nur gemäß Regeln ausgewählt, bei denen die Kardinalität und Selektivität der Spalten berücksichtigt wird. Wenn jedoch der FORCESEEK-Hinweis angegeben wird, werden derartige Regeln umgangen und diese Techniken werden stets berücksichtigt. Betrachten Sie beispielsweise die folgende Abfrage:

SELECT * FROM T WITH(FORCESEEK) WHERE T.a = 1 AND T.b = 2;

Wenn separate, nicht gruppierte Indizes in den Spalten a und b in der T-Tabelle vorhanden sind, kann ein Indexschnittstellenplan gewählt werden. Der Plan enthält also einen nicht gruppierten Indexsuchvorgang in der a-Spalte sowie einen nicht gruppierten Indexsuchvorgang in der b-Spalte, und der Plan bildet eine Schnittmenge aus den resultierenden Indexschlüsselsätzen, bevor er einen Suchvorgang in der Basistabelle durchführt.

Im folgenden Beispiel ist ein Indexvereinigungsplan ausgewählt. Der Plan enthält also einen Suchvorgang in der a-Spalte sowie einen Suchvorgang in der b-Spalte, und der Plan vereinigt die resultierenden Indexschlüsselsätze, bevor er einen Suchvorgang in der Basistabelle durchführt.

SELECT * FROM T WITH(FORCESEEK) WHERE T.a = 1 OR T.b = 2;

Verwenden von FORCESEEK in Abfragen, die LIKE oder IN verwenden

Regeln des Abfrageoptimierers und unzureichende Kardinalitätsschätzungen können zur Folge haben, dass der Optimierer anstelle einer Indexsuche einen Tabellen- oder Indexscanvorgang ausführt, wenn bei einer Abfrage IN oder LIKE als Suchprädikat verwendet wird.

Im folgenden Beispiel wird veranschaulicht, wie der FORCESEEK-Hinweis den Abfrageoptimierer zwingen kann, einen Indexsuchvorgang anstelle eines Tabellenscans durchzuführen, wenn LIKE oder IN als Suchprädikat verwendet wird. Klicken Sie zum Anzeigen der Abfrageausführungspläne auf die Symbolleistenschaltfläche Tatsächlichen Ausführungsplan einschließen, bevor Sie das Beispiel ausführen.

USE tempdb;
GO
DROP TABLE t;
GO
CREATE TABLE t(i int UNIQUE, j int, vc varchar(100));
CREATE INDEX t_vc ON t(vc);
GO
DECLARE @p1 int, @p2 int, @p3 int, @p4 int, @p5 int;
SELECT * FROM t WHERE i IN (@p1, @p2, @p3, @p4, @p5);
GO
DECLARE @p1 int, @p2 int, @p3 int, @p4 int, @p5 int;
SELECT * FROM t WITH (FORCESEEK) WHERE i IN (@p1, @p2, @p3, @p4, @p5);
GO
SELECT * FROM t WHERE vc LIKE 'Test%';
GO
SELECT * FROM t WITH (FORCESEEK) WHERE vc LIKE 'Test%';
GO
DECLARE @vc varchar(100);
SELECT * FROM t WHERE vc LIKE @vc;
GO
DECLARE @vc varchar(100);
SELECT * FROM t WITH (FORCESEEK) where vc like @vc;
GO

Verwenden von FORCESEEK in Sichten

FORCESEEK kann mit oder ohne einem Indexhinweis angegeben werden. Wenn Sie einen FORCESEEK-Tabellenhinweis auf eine Sicht oder eine indizierte Sicht anwenden, wird der FORCESEEK-Hinweis rekursiv über alle Tabellen in der erweiterten Version der Sicht weitergegeben. Der Indexhinweis wird ignoriert, falls angegeben. Wenn die zugrunde liegenden Tabellen nicht über mindestens jeweils einen Index verfügen, wird kein Plan gefunden, und der Fehler 8622 wird zurückgegeben.

Wenn Sie die FORCESEEK- und NOEXPAND-Hinweise gemeinsam in einem Verweis auf eine indizierte Sicht verwenden, wird die indizierte Sicht verwendet, ohne sie zuerst zu erweitern. Der FORCESEEK-Hinweis wird direkt auf die indizierte Sicht angewendet, die genau so wie eine Tabelle behandelt wird.

Wenn Sie einen FORCESEEK-Hinweis auf einen Tabellenverweis anwenden, kann der Tabellenverweis nicht an Vergleichen von indizierten Sichten teilnehmen. Andere Teile der Abfrage, auf die sich der FORCESEEK-Hinweis nicht auswirkt, können jedoch an Vergleichen von indizierten Sichten teilnehmen. Dies ist vergleichbar mit dem Verhalten des Vergleichs von indizierten Sichten bei Verwendung mit INDEX-Hinweisen.

Überlegungen zu bewährten Methoden

Wir empfehlen die folgenden bewährten Methoden:

  • Stellen Sie vor dem Verwenden des FORCESEEK-Tabellenhinweises 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 jeden Benutzerdatenbank auf ON (der Standard) festzulegen. Alternativ können Sie Statistiken in einer Tabelle oder Sicht mithilfe der UPDATE STATISTICS-Anweisung manuell aktualisieren.

  • Analysieren Sie die Abfrage hinsichtlich Elementen, durch die unzureichende Kardinalitäts- oder Kostenschätzungen verursacht werden können, und entfernen sie diese Elemente, sofern möglich. Ersetzen Sie beispielsweise lokale Variablen durch Parameter oder Literale, und schränken Sie die Verwendung von Tabellenwertfunktionen und Tabellenvariablen mit mehreren Anweisungen in der Abfrage ein. Weitere Informationen über andere zu suchende Elemente finden Sie unter Statistics Used by the Query Optimizer in Microsoft SQL Server 2005 (in Englisch).

  • 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.