Index SEEK wird nur verwendet, wenn OPTION (RECOMPILE)?

11

(Frage von SO verschoben)

Ich habe eine Tabelle (Dummy-Daten) mit Clustered-Index enthält 2 Spalten:

Geben Sie hier die Bildbeschreibung ein

Jetzt führe ich diese beiden Abfragen aus:

declare 
@productid int =1 , 
@priceid  int = 1




SELECT productid,
       t.priceID
FROM   Transactions AS t
WHERE  (productID = @productid OR @productid IS NULL)
       AND (priceid = @priceid OR @priceid IS NULL)  


SELECT productid,
       t.priceID
FROM   Transactions AS t
WHERE  (productID = @productid)
       AND (priceid = @priceid)

Der tatsächliche Ausführungsplan für beide Abfragen lautet:

Geben Sie hier die Bildbeschreibung ein

Wie Sie sehen können, verwendet der erste SCAN, während der zweite SEEK verwendet.

Durch Hinzufügen OPTION (RECOMPILE)zur ersten Abfrage wurde der Ausführungsplan jedoch auch zur Verwendung von SEEK:

Geben Sie hier die Bildbeschreibung ein

Freunde im DBA-Chat sagten mir:

In Ihrer Abfrage ist @ productid = 1, was bedeutet, dass (productID = @ productID ODER @productID IS NULL) zu (productID = @ productID) vereinfacht werden kann. Ersteres erfordert einen Scan, um mit einem beliebigen Wert von @productID zu arbeiten, letzteres könnte eine Suche verwenden. Wenn Sie also RECOMPILE verwenden, überprüft SQL Server, welchen Wert Sie tatsächlich in @productID haben, und erstellt den besten Plan dafür. Mit einem Wert ungleich Null in @productID ist eine Suche am besten. Wenn der Wert von @productID unbekannt ist, muss der Plan einem beliebigen Wert in @productID entsprechen, für den ein Scan erforderlich wäre. Seien Sie gewarnt: OPTION (RECOMPILE) erzwingt bei jeder Ausführung eine Neukompilierung des Plans, wodurch jeder Ausführung einige Millisekunden hinzugefügt werden. Dies ist jedoch nur dann ein Problem, wenn die Abfrage sehr häufig ausgeführt wird.

Ebenfalls :

Wenn @productID null ist, welchen Wert würden Sie suchen? Antwort: Es gibt nichts zu suchen. Alle Werte qualifizieren sich.

Ich verstehe, dass OPTION (RECOMPILE)SQL Server gezwungen ist, zu sehen, welche tatsächlichen Werte die Parameter haben, und zu prüfen, ob es damit suchen kann.

Aber jetzt verliere ich den Vorteil der Vorauskompilierung.

Frage

IMHO - SCAN wird nur ausgeführt, wenn ein Parameter null ist.
Das ist in Ordnung - lassen Sie SQL SERVER einen Ausführungsplan für SCAN erstellen.
ABER wenn SQL Server sieht, dass ich diese Abfrage viele Male mit Werten 1,1ausführe : Warum erstellt es dann keinen weiteren Ausführungsplan und verwendet dafür SEEK?

AFAIK - SQL erstellt einen Ausführungsplan für die am häufigsten getroffenen Abfragen .

  • Warum speichert SQL SERVER keinen Ausführungsplan für:

    @productid int =1 , @priceid int = 1

(Ich führe es viele Male mit diesen Werten aus)

  • Ist es möglich, SQL zu zwingen, diesen Ausführungsplan (der SEEK verwendet) für zukünftige Aufrufe beizubehalten?

Vollständiges Tabellenskript + Daten erstellen

Royi Namir
quelle
2
Lassen Sie uns diese Diskussion im Chat fortsetzen .
Ypercubeᵀᴹ

Antworten:

10

Fassen wir einige der wichtigsten Punkte unserer Chatroom-Diskussion zusammen :


Im Allgemeinen speichert SQL Server für jede Anweisung einen einzelnen Plan zwischen . Dieser Plan muss für alle möglichen zukünftigen Parameterwerte gültig sein .

Es ist nicht möglich, einen Suchplan für Ihre Abfrage zwischenzuspeichern, da dieser Plan nicht gültig wäre, wenn beispielsweise @productid null ist.

In einigen zukünftigen Versionen unterstützt SQL Server möglicherweise einen einzelnen Plan, der abhängig von den Laufzeitparameterwerten dynamisch zwischen einem Scan und einer Suche wählt. Dies ist jedoch heute nicht der Fall.

Allgemeine Problemklasse

Ihre Abfrage ist ein Beispiel für ein Muster, das als "Catch All" - oder "Dynamic Search" -Abfrage bezeichnet wird. Es gibt verschiedene Lösungen mit jeweils eigenen Vor- und Nachteilen. In modernen Versionen von SQL Server (2008+) sind die Hauptoptionen:

  • IF Blöcke
  • OPTION (RECOMPILE)
  • Dynamisches SQL mit sp_executesql

Die umfassendste Arbeit zu diesem Thema stammt wahrscheinlich von Erland Sommarskog, die in den Referenzen am Ende dieser Antwort enthalten ist. Es gibt keinen Ausweg aus der Komplexität, daher ist es notwendig, einige Zeit in das Ausprobieren jeder Option zu investieren, um die jeweiligen Kompromisse zu verstehen.

IF Blöcke

Um eine IFBlocklösung für den speziellen Fall in der Frage zu veranschaulichen :

IF @productid IS NOT NULL AND @priceid IS NOT NULL
BEGIN
    SELECT 
        T.productID,
        T.priceID
    FROM dbo.Transactions AS T
    WHERE
        T.productID = @productid
        AND T.priceID = @priceid;
END;
ELSE IF @productid IS NOT NULL
BEGIN
    SELECT 
        T.productID,
        T.priceID
    FROM dbo.Transactions AS T
    WHERE
        T.productID = @productid;
END;
ELSE IF @priceid IS NOT NULL
BEGIN
    SELECT 
        T.productID,
        T.priceID
    FROM dbo.Transactions AS T
    WHERE
        T.priceID = @priceid;
END;
ELSE
BEGIN
    SELECT 
        T.productID,
        T.priceID
    FROM dbo.Transactions AS T;
END;

Diese enthält eine separate Anweisung für die vier möglichen Null- oder Nicht-Null-Fälle für jeden der beiden Parameter (oder lokalen Variablen), sodass es vier Pläne gibt.

Dort gibt es ein potenzielles Problem beim Parameter-Sniffing, für das möglicherweise ein OPTIMIZE FORHinweis zu jeder Abfrage erforderlich ist . Weitere Informationen zu diesen Feinheiten finden Sie im Abschnitt "Referenzen".

Neu kompilieren

Wie oben und in der Frage erwähnt, können Sie auch einen OPTION (RECOMPILE)Hinweis hinzufügen , um bei jedem Aufruf einen neuen Plan (Suchen oder Scannen) zu erhalten. Angesichts der relativ langsamen Häufigkeit von Anrufen in Ihrem Fall (durchschnittlich alle zehn Sekunden mit einer Kompilierungszeit von weniger als einer Millisekunde) ist diese Option wahrscheinlich für Sie geeignet:

SELECT
    T.productID,
    T.priceID
FROM dbo.Transactions AS T
WHERE
    (T.productID = @productid OR @productid IS NULL)
    AND (T.priceID = @priceid OR @priceid IS NULL)
OPTION (RECOMPILE);

Es ist auch möglich, Funktionen aus den oben genannten Optionen auf kreative Weise zu kombinieren, um die Vorteile jeder Methode optimal zu nutzen und gleichzeitig die Nachteile zu minimieren. Es gibt wirklich keine Abkürzung, um dieses Zeug im Detail zu verstehen und dann eine fundierte Entscheidung zu treffen, die durch realistische Tests unterstützt wird.

Weiterführende Literatur

Paul White 9
quelle