2010-12-16 5 views
25

Ich habe eine Ansicht, die 2 Ints aus einer Tabelle mit einem CTE zurückgibt. Wenn ich die Ansicht wie diese Abfrage läuft es in weniger als einer SekundeSQL Server-Abfrage: Schnell mit Literal, aber langsam mit Variable

SELECT * FROM view1 WHERE ID = 1 

Allerdings, wenn ich die Ansicht wie diese Abfrage dauert es 4 Sekunden.

DECLARE @id INT = 1 
SELECT * FROM View1 WHERE ID = @id 

Ich habe die 2 Abfragepläne überprüft und die erste Abfrage wird ein Clustered-Index suchen auf der Haupttabelle Durchführung der Rückkehr 1 Datensatz dann den Rest der Ansicht Abfrage auf diese Ergebnismenge Anwendung, wo als die zweite Abfrage führt einen Index-Scan durch, der ungefähr 3000 Datensätze zurückgibt, anstatt nur den einen, an dem ich interessiert bin, und später den Ergebnissatz zu filtern.

Gibt es etwas Offensichtliches, dass ich vermisse, um zu versuchen, die zweite Abfrage den Index Seek anstelle eines Index-Scan zu verwenden. Ich benutze SQL 2008, aber alles, was ich tue, muss auch auf SQL 2005 laufen. Zuerst dachte ich, es wäre ein Problem mit dem Parameter-Sniffing, aber ich bekomme die gleichen Ergebnisse, selbst wenn ich den Cache lösche.

+0

Welcher Datentyp ist ID? – gbn

+0

es ist ein INT-Feld – Gavin

Antwort

27

Wahrscheinlich ist es, weil im Parameter Fall kann der Optimierer nicht wissen, dass der Wert nicht null ist, so muss es einen Plan erstellen, die auch korrekte Ergebnisse zurückgibt, wenn es ist. Wenn Sie über SQL Server 2008 SP1 verfügen, können Sie versuchen, der Abfrage OPTION(RECOMPILE) hinzuzufügen.

+2

+1 Funktioniert wie ein Champion hier (und viel weniger manuell als der Versuch, verschiedene Joins/Pläne usw. zu erzwingen) –

+1

@ pst - Dies ist die richtige vorgeschlagene Lösung, aber falsche Argumentation. Das OP hat eine Variable und keinen Parameter. Und das Problem sind Selektivitätsschätzungen, da SQL Server kein variables Sniffing durchführt. Nicht "Erstellen eines Plans, der sich mit' NULL' befasst " –

+0

@MartinSmith All die kleinen Details, die mir entgehen :(Alles, was ich weiß ist, dass SQL Server war glücklich eine 2 Sekunden (in SMSS-Abfrage) in eine Ich-werde- stop-it-nach-10-Minuten-Abfrage eines SqlCommand (mit Platzhaltern) als Teil eines typisierten DataSet.Ich aktualisierte alle Statistiken (ohne Optionen) auf die verwandten Tabellen vor dem Versuch der 'OPTION (RECOMPILE)' Route, aber das schien das Problem nicht zu beheben Was ist mit dem "Erstellen eines Plans, der sich mit NULL beschäftigt" gemeint? –

2

Sie könnten Ihrer Abfrage ein OPTIMIZE FÜR hint hinzufügen, z.

DECLARE @id INT = 1 
SELECT * FROM View1 WHERE ID = @id OPTION (OPTIMIZE FOR (@ID = 1)) 
1

Wenn SQL beginnt, den Abfrageplan für die Abfrage mit der Variablen zu optimieren, wird der verfügbare Index mit der Spalte verglichen. In diesem Fall gab es einen Index, so dass SQL annahm, dass er nur den Index nach dem Wert durchsuchen würde. Wenn SQL den Plan für die Abfrage mit der Spalte und einem Literalwert erstellte, konnte er sich die Statistiken und den Wert ansehen, um zu entscheiden, ob er den Index durchsuchen sollte oder ob eine Suche korrekt wäre.

Mithilfe des Optimierungshinweises und eines Werts wird SQL mitgeteilt, dass "dies der Wert ist, der die meiste Zeit verwendet wird, um diesen Wert zu optimieren" und ein Plan so gespeichert wird, als ob dieser Literalwert verwendet würde. Wenn Sie den Optimierungshinweis und den Unterhinweis UNKNOWN verwenden, teilt SQL Ihnen mit, dass Sie nicht wissen, wie der Wert sein wird. Daher prüft SQL die Statistiken für die Spalte und entscheidet, was, suchen oder scannen, am besten ist und den Plan entsprechend erstellt.

0

Dasselbe Problem ist mir selbst aufgefallen, und es stellte sich heraus, dass es sich um einen fehlenden Index handelte, der eine (linke) Verknüpfung des Ergebnisses einer Unterabfrage beinhaltete.

select * 
from foo A 
left outer join (
    select x, count(*) 
    from bar 
    group by x 
) B on A.x = B.x 

Added ein Index namens bar_x für bar.x

2

In meinem Fall in DB-Tabelle Spaltentyp wurde als VarChar und in parametrisierte Abfrage Parametertyp definiert als NVarChar definiert wurde, diese CONVERT_IMPLICIT in der tatsächlichen Ausführung eingeführt Planen Sie, den Datentyp vor dem Vergleich übereinstimmen und das war der Schuldige für die Leistung der Sau, 2 Sekunden vs 11 Sekunden. Nur die Korrektur des Parametertyps machte die parametrisierte Abfrage so schnell wie die nicht parametrisierte Version.

Hoffe, das kann jemand mit ähnlichen Problem helfen.

0

Ich lief in dieses Problem selbst mit Blick auf die < 10ms mit einer direkten Zuordnung lief (WHERE UtilAcctId = 12345), aber mit einer variablen Zuordnung so lange über 100 Mal nahm (WHERE UtilAcctId = @UtilAcctId) .
Der Ausführungsplan für Letzteres war nicht anders als wenn ich die Ansicht auf die gesamte Tabelle ausgeführt hätte.

Meine Lösung benötigt keine Tonnen von Indizes, Optimizer-Hints oder ein langes Statistik-Update.

Stattdessen konvertierte ich die Ansicht in eine Benutzer-Table-Funktion wobei die Parameter der Wert auf der WHERE-Klausel erforderlich waren. In der Tat war diese WHERE-Klausel 3 Abfragen tief verschachtelt und es funktionierte immer noch und es war wieder auf die < 10ms Geschwindigkeit.

Schließlich habe ich den Parameter geändert, um ein TYPE zu sein, der eine Tabelle von UtilAcctIds (int) ist. Dann kann ich die WHERE-Klausel auf eine Liste aus der Tabelle beschränken. WHERE UtilAcctId = [Parameter-Liste] .UtilAcctId. Das funktioniert noch besser. Ich denke, die user-table-Funktionen sind vorkompiliert.

Verwandte Themen