2012-10-19 3 views
7

an dieser Geige Werfen Sie einen Blick: http://sqlfiddle.com/#!6/18324/2SQL Server verwenden statt suchen scannen, wenn eine Fensterfunktion und Prädikat enthält eine Variable

den ersten Ausführungsplan erweitern, für die Abfragen gegen Ansicht B.
Beachten Sie, dass die erste Abfrage mit der Indexsuche ausgeführt wird, während die zweite mit Indexsuche ausgeführt wird. In meinem realen Setup mit Tausenden von Zeilen erzeugt dies einen beträchtlichen Leistungseinbruch.

WTF ???

Die Abfragen sind gleichwertig, nicht wahr? Warum erzeugt ein Literal Suche und eine Variable - scan?
Aber noch wichtiger: wie kann ich um diese umgehen?

This post kommt dem Problem am nächsten, und die Lösung, die von dort funktioniert, ist option(recompile) (danke, Martin Smith). Dies funktioniert jedoch nicht für mich, da meine Abfragen von meiner ORM-Bibliothek (Entity Framework) generiert werden und ich sie nicht manuell ändern kann.
Eher, was ich suche, ist eine Möglichkeit, die B Ansicht neu zu formulieren, so dass das Problem nicht auftreten würde.

Beim Hantieren mit diesem Problem habe ich bemerkt, dass immer der "Segment" -Block im Ausführungsplan das Prädikat verliert. Um dies zu überprüfen, habe ich die Abfrage in Form einer Unterabfrage mit der Funktion min umformuliert (siehe Ansicht). Und voila! - Beide Abfragen gegen die Sicht produzieren identische Pläne.

Die schlechte Nachricht ist jedoch, dass ich nicht diesen min -gestützte Trick, weil in meinem realen Setup verwenden kann, die Spalte Y tatsächlich mehrere Spalten sind, so dass ich von ihnen bestellen kann, aber ich kann ein nicht nehmen min() von ihnen.
Also die zweite Frage wäre: kann jemand mit einem Trick kommen, der Min-powered Unterabfrage ähnelt, aber für mehrere Spalten funktioniert?

HINWEIS 1: Dies ist definitiv nicht auf den Wendepunkt bezogen, da es nur 2 Datensätze in der Tabelle gibt.
HINWEIS 2: es hat auch nicht mit dem Vorhandensein einer Ansicht zu tun. Sehen Sie sich ein Beispiel mit der Ansicht C an: Der Server verwendet in diesem Fall glücklich die Suche.

+2

Auf meiner lokalen 2008 R2-Instanz 'wählen * aus B, wobei X = @ eine Option (rekompilieren)' erzeugt eine Suche. –

+0

@Martin Smith: Richtig. Verpasst das. Vielen Dank. Leider funktioniert das jedoch nicht ganz. Siehe mein Update zu der Frage. –

+0

Ziemlich wahrscheinlich ein Duplikat: http://dba.stackexchange.com/questions/12498/window-functions-cause-awful-execution-plan-when-called-from-a-view-with-externa – GSerg

Antwort

0

Hier ist meine eigene Antwort.

Letztlich habe ich den min -gestützte Trick, und ich habe um die Tatsache, dass Y tatsächlich mehrere Spalten ist durch die Spalten in konstanter Länge String-Darstellungen (sorgfältig abgestimmt für die Sortierung) Umwandeln und diese Zeichenfolgen zusammen in einem String-Beitritt . Danach kann ich diese verbundene Zeichenfolge als Argument für min() verwenden.

Ich möchte immer noch den richtigen Weg wissen, dies zu tun. Wenn jemand es zufällig weiß, würde ich mich freuen.

0

Kann sein, das wird man arbeiten

select a.X, a.Y from A a 
    cross apply 
     (select top 1 * from A t where t.X = a.X order by t.Y asc) as idx 

SQLFiddle http://sqlfiddle.com/#!6/a3362/2

+0

Versucht, dass eine. Es ist wahr, es erzeugt eine Suche. Aber es produziert ZWEI von ihnen, und dann eine verschachtelte Schleifen zwischen diesen beiden. –

+0

hast du das in der realen umgebung probiert? Es sollte fast so schnell wie Min-Trick sein –

+0

Nein, ich habe es nicht in einer realen Umgebung versucht, aber ich sehe nicht, wie es fast so schnell sein soll. Es macht zwei Suchen statt einer plus eine extra Verbindung, also sollte es mindestens doppelt so komplex sein, nicht wahr? –

0

Die Abfragen äquivalenten Ausgang erzeugen, aber in the eyes of the sql optimizer they are different. Der Artikel empfiehlt Blick auf die OPTION clause (unfortunately not included before SQL 2005).

Sie können Brew Your Own Query on top of the Entity Framework, die sein kann Ihre beste Wette, um die gewünschte Leistung zu erzielen.

+2

Wenn der SQL-Server zwei Werte verschiedener Typen vergleichen muss, verwendet er Regeln, um zu wissen, wie die Umwandlung durchgeführt wird. http://msdn.microsoft.com/en-us/library/ms190309.aspx. Wenn SQL Server varchar und uniqueidentifier vergleicht, wird VARCHAR an uniqueidentifier übergeben. Wenn Sie also 'X = '40DB7DE2-EEFA-4D31-B400-7E72AB34DE99'' schreiben und X uniqueidentifier ist, dann wird meand' X = cast (' 40DB7DE2- EEFA-4D31-B400-7E72AB34DE99 'als Uniqueidentifier' Hier ist SQLFiddle mit zwei Abfragen - eine mit Varchar und eine mit Uniqueidentifier - die Pläne sind gleich http://sqlfiddle.com/#!6/18324/19 –

+2

@ RyanGates : Erstens ist die Vorstellung "es gibt eine Konvertierung für jeden Datensatz" einfach nicht wahr. Zweitens ist es tatsächlich die erste Abfrage (diejenige mit Literal), die so ausgeführt wird, wie ich es ausführen möchte, während die zweite Abfrage (mit Variable) eine schlechtere Leistung zeigt. –

Verwandte Themen