Wie kann man Kreuz anwenden, um eine Ansicht zeilenweise zu bearbeiten?

7

Wir haben eine Ansicht, die für Einzelelementabfragen optimiert ist (200 ms keine Parallelität):

select * 
    from OptimizedForSingleObjectIdView e2i
   where ObjectId = 3374700

Es funktioniert auch mit kleinen Mengen statischer IDs (~ 5).

select * 
    from OptimizedForSingleObjectIdView e2i
   where ObjectId in (3374700, 3374710, 3374720, 3374730, 3374740);

Wenn die Objekte jedoch von einer externen Quelle stammen, wird ein langsamer Plan generiert. Der Ausführungsplan zeigt, dass der Ausführungszweig für den Ansichtsteil das Prädikat für ObjectId ignoriert, während er sie im ursprünglichen Fall zum Ausführen von Indexsuchen verwendet.

select v.*
  from 
     (
       select top 1 ObjectId from Objects
        where ObjectId % 10 = 0
        order by ObjectId
     ) o  
  join OptimizedForSingleObjectIdView v -- (also tried inner loop join)
    on v.ObjectId = o.ObjectId;

Wir möchten nicht in "dual" investieren, um die Ansicht für nicht singuläre Fälle zu optimieren. Die Lösung, die wir "suchen", besteht vielmehr darin, die Ansicht wiederholt einmal pro Objekt aufzurufen, ohne auf einen SP zurückzugreifen .

Meistens ruft die folgende Lösung die Ansicht zeilenweise auf. Allerdings diesmal nicht und nicht einmal für nur 1 Objekt:

select v.*
  from
     (
       select top 1 ObjectId 
         from Objects 
        where ObjectId % 10 = 0 -- non-trivial predicate
        order by ObjectId
     ) o
   cross apply
    (
      select top 2000000000 *
        from OptimizedForSingleObjectIdView v_
       where ObjectId = o.ObjectId 
       order by v_.SomeField
    ) v;

Zu einer Zeit dachte ich, es gäbe eine Behauptung, dass Cross Apply für die zeilenweise Ausführung garantiert sei, wenn eine UDF aufgerufen wird, aber dies schlug auch fehl:

create function FunctionCallingView(@pObjectId bigint)
returns table
as 
return select *
  from OptimizedForSingleObjectIdView 
 where ObjectId = @pObjectId;             

select v.*
  from
     (
       select top 1 ObjectId 
         from Objects 
        where ObjectId % 10 = 0
        order by ObjectId
     ) o
 cross apply FunctionCallingView(o.ObjectId) v

Das Hinzufügen einer Option (Reihenfolge erzwingen) hat nicht geholfen - es gibt jedoch bereits zwei Hash-Hinweise in der Ansicht. Das vorübergehende Entfernen half nicht und verlangsamte den Einzelfall.

Hier ist ein Ausschnitt des geschätzten Plans für den funktionsbasierten langsamen Fall. Die Schätzung von 1 Zeile ist korrekt. Weit rechts (nicht gezeigt) befindet sich ein Suchprädikat, das dieses Top-1-Ergebnis nicht enthält. Dies scheint anderen Fällen ähnlich zu sein, in denen einzelne untersuchte Werte aus Tabellensuchen nicht anderswo als Suchprädikate verwendet werden.

Geben Sie hier die Bildbeschreibung ein

crokusek
quelle
Was passiert, wenn Sie einen OPTION(FAST 1)Hinweis verwenden?
Erik Darling
@ErikDarling keine Änderung afaict.
Crokusek
Meine Güte, ich habe 2012 fast die gleiche Frage gestellt. Schließen, es sei denn, jemand hat neue Informationen. Das Umschließen der Ansicht mit einer UDF mit mehreren Anweisungen sollte funktionieren, obwohl sie eine umfangreiche Syntax aufweist, da die Ansicht definiert werden muss. Natürlich wird das Parallelität im Jahr 2012 verhindern.
crokusek

Antworten:

10

Es ist nicht möglich, die Auswertung der Ansicht pro Zeile der äußeren Abfrage vollständig zu garantieren , ohne etwas zu verwenden, das einen neuen T-SQL-Ausführungsbereich einführt, z. B. eine nicht inline (Funktion mit mehreren Anweisungen BEGIN...END) Tabellenwert. Dies ist so ziemlich der Ratschlag, der als Antwort auf Ihre vorherige Frage gegeben wurde. So verwenden Sie Zusammenführungshinweise, um komplexe Abfragen in SQL Server zu isolieren .

Zu einer Zeit dachte ich, es gäbe eine Behauptung, dass Cross Apply für die zeilenweise Ausführung garantiert ist, wenn eine UDF aufgerufen wird

Dies gilt nicht für Inline- Tabellenwertfunktionen, da die Definition vor Beginn der Optimierung in die aufrufende Abfrage erweitert wird.


Es gibt jedoch einige Dinge, die Sie tun können, um das gewünschte Ergebnis nachdrücklich zu fördern.

Der Ausführungsplan zeigt, dass der Ausführungszweig für den Ansichtsteil das Prädikat ignoriert, ObjectIdwährend er sie im ursprünglichen Fall zum Ausführen von Indexsuchen verwendet.

Sie erwarten, dass die ObjectIdWerte "innerhalb der Ansicht" mithilfe von Indexsuchen für jede Fahrzeile ausgewertet werden. Dies ist der Ausführungsstil für korrelierte verschachtelte Schleifen (Anwenden). Beachten Sie, dass die Verwendung des APPLYT-SQL-Sprachelements nicht garantiert, dass bei der physischen Ausführung der Apply-Stil verwendet wird.

Es hört sich sehr danach an, als würde SQL Server stattdessen die ObjectIdWerte ausführen, die beim Operator Nested Loops Join getestet wurden . Dies ist ein nicht korreliertes oder naives, verschachteltes Loop-Join-Ausführungsmuster.

Dies wird höchstwahrscheinlich durch die Verknüpfungshinweise verursacht, die Sie in der Ansicht verwenden. Verknüpfungshinweise sind im Allgemeinen zu vermeiden, da sie die Optimierungsfreiheit nicht nur für den physischen Verbindungstyp stark einschränken. Insbesondere erzwingen Verknüpfungshinweise auch die Reihenfolge der Verknüpfungen für die gesamte Abfrage (als hätten Sie einen FORCE ORDERHinweis verwendet) und verhindern mehrere Optimierungen in Bezug auf die Platzierung und Strategie der Aggregation und vieles mehr.

Wenn Sie wirklich müssen Hinweise in einer Ansicht beitreten (etwas würde ich dringend empfehlen, im Allgemeinen vermeiden), könnten Sie die zuverlässigste Weg finden , die Grundrißform Sie wünschen zu erhalten ist:

  1. Erstellen Sie eine inline ( RETURNS TABLE) -Funktion mithilfe der Ansichtsdefinition (ohne auf die Ansicht zu verweisen).
  2. Geben Sie @ObjectIdals Parameter für die Funktion an.
  3. Platzieren eines Prädikats mithilfe des Parameters im Funktionskörper so, dass eine Indexsuche wahrscheinlicher wird.
  4. Ein FORCESEEKTabellenhinweis innerhalb der Funktion kann verwendet werden, wenn wirklich jede Verwendung zu einer Suche führen sollte.
  5. Rufen Sie die neue Inline-Funktion mit auf APPLY.

Ich mag es im Allgemeinen nicht, bestimmte Syntaxen und Hinweise zu verwenden, um eine bestimmte physische Planform zu erzwingen. Sie können allgemeineren Erfolg haben, indem Sie Abfragen parametrisieren und die Planform mithilfe eines Planleitfadens garantieren.

Paul White 9
quelle
Es funktionierte mit (1,2,3), aber das Platzieren des Prädikats am Ende der Ansichtsdefinition innerhalb der ITVF funktionierte nicht mit der Kreuzanwendung, obwohl es eigenständig funktioniert, wenn die IVTF eine wörtliche ObjectId übergibt. Wenn die vorherigen Hash-Hinweise entfernt wurden, schlägt dies in allen Fällen fehl. Die Rettung besteht darin, dass die ITVF die syntaktische Verschiebung des Prädikats früher in der Kette ermöglicht. Ich wünschte, es gäbe ein Kreuz mit einem "starren" Hinweis.
Crokusek
Kann eine Planführung verwendet werden, um nur einen bestimmten Teil des Plans zu formen, sodass sich der Rest weiterentwickeln kann, oder wird der gesamte Plan gesperrt? Mein erster Eindruck von der Verwendung von PGs über ein paar verstreute Hinweise ist die (1) anfängliche Einrichtungszeit und (2) technische Hürde, die der nächste Entwickler benötigt, um sie aufrechtzuerhalten. Es sieht so aus, als würde eine Änderung der Ansicht in der Zukunft eine Neuerstellung von Plan und Analyse usw. bewirken. Die abstrakte Korrelation zwischen Syntax und Ausführung ist gut, bis ein Hinweis unvermeidlich ist. Aber sobald die Syntax an den Plan gebunden ist (nach dem Neuanordnen), ist dies ein Vorteil für die Zukunft.
Crokusek
Um die Schleife zu vervollständigen, wurde eine Ansicht erstellt, die alle möglichen ObjectIds verbindet und sie kreuzweise auf die ITVF anwendet. Jetzt scheint diese neue Ansicht als Standardverknüpfung überall Plug-and-Play zu sein, ohne dass eine Kreuzanwendung erforderlich ist.
Crokusek
1
"syntaktische Bewegung des Prädikats" ist genau mein Vorschlag. Ich kann die anderen Dinge nicht wirklich kommentieren, da sie von Details abhängen, die nur Sie an dieser Stelle sehen können. Wenn Sie mehr Details wünschen, geben Sie in Ihrer Frage einige Details an, und ich werde einen weiteren Blick darauf werfen. Planleitfäden gelten für eine ganze Aussage.
Paul White 9