Die Abfrage:
SELECT Object1.Column1, Object2.Column2 AS Column3, Object2.Column4 AS Column5,
Object3.Column6, Object3.Column7,Object1.Column8, Object1.Column9,
Object1.Column10, Object1.Column11, Object1.Column12, Object1.Column13,
Object1.Column14, Object1.Column15 as Column15, Object1.Column16,
Object4.Column4 AS Column17, Object4.Column2 AS Column18, Object1.Column19,
Object1.Column20, Object1.Column21, Object1.Column22, Object1.Column23,
Object1.Column24, Object1.Column25, Object1.Column26, Object5.Column4,
Object1.Column27, Object1.Column28, Object1.Column29, Object3.Column30,
Object3.Column1 as Column31, Object3.Column32 as Column33, Object1.Column34
as Column34, ? AS Column35 , Object3.Column36 as Column37
FROM Object6 AS Object1
INNER JOIN Object7 AS Object3 ON Object1.Column38 = Object3.Column1
INNER JOIN Object8 AS Object2 ON Object3.Column30 = Object2.Column1
LEFT JOIN Object9 AS Object4 ON Object1.Column16 = Object4.Column2
LEFT JOIN Object10 AS Object5 ON Object1.Column9 = Object5.Column2
WHERE Object2.Column1 <> ? AND Object1.Column8 = ?
AND ( coalesce(Column16,?)= ? )
AND EXISTS (
SELECT ?
FROM Object11
WHERE Column39 = ?
AND Column30 = Object3.Column30)
ORDER BY Column7 desc
OFFSET ? ROWS FETCH FIRST ? ROWS ONLY
Ich weiß, dass ich vielleicht einen Index dazu hinzufügen sollte:
Database1.Schema1.Object7.Column30, Database1.Schema1.Object7.Column36, Database1.Schema1.Object7.Column6, Database1.Schema1.Object7.Column32
Eine dieser Spalten ist jedoch eine Varchar 4000 und kann aufgrund der großen Dimension des Feldes nicht erstellt werden.
Ich habe festgestellt, dass es nur 25 Sekunden dauert, wenn die zurückgegebenen Zeilen kleiner sind als die erste Abrufnummer
sql-server
query-performance
execution-plan
sql-server-2017
Gabriele D'Onufrio
quelle
quelle
OPTION(FORCE ORDER)
zu Ihrer Anfrage hinzuzufügenAntworten:
Der Ausführungsplan greift
Object7
zuerst mit einem nicht abdeckenden Index derColumn7
Reihe nach zu. Anschließend werden einige Schlüsselsuchen für diese Tabelle durchgeführt und verschachtelte Schleifen werden mit den anderen Tabellen verknüpft, wobei die endgültige Verknüpfung zu demTOP
Operator führt, der noch von bestellt wurdeColumn7
.Sobald dies genügend Zeilen empfangen hat, um die
OFFSET ... FETCH
Anforderungen zu erfüllen , kann es aufhören, weitere Zeilen von nachgeschalteten Betreibern anzufordern. SQL Server schätzt, dass ab dem ersten Index nur 2419 Zeilen gelesen werden müssen,Object7.Column7
bevor dieser Punkt erreicht ist.Diese Schätzung ist überhaupt nicht korrekt. Tatsächlich liest es die Gesamtheit
Object7
aller Zeilen und es gehen ihnen wahrscheinlich die Zeilen aus, bevor dasOFFSET ... FETCH
erfüllt ist.Der Semi-Join-On
Object11
reduziert die Anzahl der Zeilen um fast die Hälfte, aber der Killer ist der Join-OnObject6
und das Prädikat auf demselben Tisch. Zusammen reduzieren diese die9,753,116
aus dem Semijoin kommenden Reihen auf2
.Sie können versuchen, einige Zeit mit Statistiken zu den beteiligten Tabellen zu verbringen, um zu versuchen, die Kardinalitätsschätzungen aus diesen Verknüpfungen genauer zu ermitteln, oder Sie können hinzufügen,
OPTION (USE HINT ('DISABLE_OPTIMIZER_ROWGOAL') )
dass der Plan kostenpflichtig ist, ohne davon auszugehen, dass er aufgrund dessenOFFSET ... FETCH
- vorzeitig beendet werden kann wird Ihnen sicherlich einen anderen Plan geben.quelle
Wenn Sie einen Index für Object11, Column39 + Column30 und einen Index für Object7, Column30 mit anderen Feldern von Object7 im
INCLUDE
Teil derCREATE INDEX
Anweisung für Object 7 hinzufügen können , sollte die Leistung erheblich gesteigert werden. Dies ist die überwiegende Mehrheit der mit dieser Abfrage verbundenen Ressourcenausgaben.Basierend auf dem XML des Plans scheinen diese nahe an den optimalen Indizes für diese Abfrage zu liegen:
quelle