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.
quelle
OPTION(FAST 1)
Hinweis verwenden?Antworten:
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 .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.
Sie erwarten, dass die
ObjectId
Werte "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 desAPPLY
T-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
ObjectId
Werte 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 ORDER
Hinweis 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:
RETURNS TABLE
) -Funktion mithilfe der Ansichtsdefinition (ohne auf die Ansicht zu verweisen).@ObjectId
als Parameter für die Funktion an.FORCESEEK
Tabellenhinweis innerhalb der Funktion kann verwendet werden, wenn wirklich jede Verwendung zu einer Suche führen sollte.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.
quelle