Warum schätzt der Verkettungsoperator weniger Zeilen als seine Eingaben?

20

Im folgenden Abfrageplan-Snippet scheint es offensichtlich, dass die Zeilenschätzung für den ConcatenationOperator ~4.3 billion rowsoder die Summe der Zeilenschätzungen für seine beiden Eingaben sein sollte.

Es wird jedoch eine Schätzung von ~238 million rowserstellt, die zu einem Suboptimum Sort/ Stream Aggregateeiner Suboptimalstrategie führt, bei der Hunderte von GB an Daten auf Tempdb übertragen werden. Eine logisch konsistente Schätzung hätte in diesem Fall zu einem Hash AggregateErgebnis geführt, das Verschütten beseitigt und die Abfrageleistung erheblich verbessert.

Ist das ein Fehler in SQL Server 2014? Gibt es gültige Umstände, unter denen eine Schätzung, die unter den Eingaben liegt, sinnvoll sein könnte? Welche Problemumgehungen sind möglicherweise verfügbar?

Bildbeschreibung hier eingeben

Hier ist der vollständige Abfrageplan (anonymisiert). Ich habe keinen Sysadmin-Zugriff auf diesen Server, um Ausgaben von QUERYTRACEON 2363oder ähnliche Ablaufverfolgungsflags bereitzustellen , kann diese Ausgaben jedoch möglicherweise von einem Administrator abrufen, wenn sie hilfreich sind.

Die Datenbank hat die Kompatibilitätsstufe 120 und verwendet daher den neuen SQL Server 2014 Cardinality Estimator.

Statistiken werden jedes Mal manuell aktualisiert, wenn Daten geladen werden. Angesichts des Datenvolumens verwenden wir derzeit die Standardabtastrate. Es ist möglich, dass sich eine höhere Abtastrate (oder FULLSCAN) auswirkt.

Geoff Patterson
quelle

Antworten:

21

So zitieren Sie Campbell Fraser zu diesem Connect-Artikel :

Diese "Kardinalitätsinkonsistenzen" können in einer Reihe von Situationen auftreten, einschließlich der Verwendung von concat. Sie können entstehen, weil die Schätzung eines bestimmten Teilbaums im endgültigen Plan möglicherweise auf einem anders strukturierten, aber logisch äquivalenten Teilbaum durchgeführt wurde. Aufgrund der statistischen Natur der Kardinalitätsschätzung kann nicht garantiert werden, dass bei der Schätzung auf verschiedenen, aber logisch äquivalenten Bäumen dieselbe Schätzung erzielt wird. Insgesamt werden also keine Garantien für die erwartete Konsistenz gegeben.

Um das ein wenig zu erweitern: Ich möchte erklären, dass die anfängliche Kardinalitätsschätzung (die vor dem Beginn der kostenbasierten Optimierung durchgeführt wird) zu "konsistenteren" Kardinalitätsschätzungen führt, da der gesamte Anfangsbaum mit jedem weiteren verarbeitet wird Schätzung direkt abhängig von der vorhergehenden.

Während Kosten-Optimierung, Teile des Plans Baum (ein oder mehrere Betreiber) mit Alternativen erforscht und ersetzt werden, von denen jeder kann eine neue Schätzung von Kardinalität erfordern. Es gibt keinen generellen Weg zu sagen, welche Schätzung im Allgemeinen besser ist als eine andere, so dass es durchaus möglich ist, einen endgültigen Plan zu erhalten, der "inkonsistent" erscheint. Dies ist einfach das Ergebnis des Zusammenfügens von "Plänen", um die endgültige Anordnung zu bilden.

Trotzdem gab es einige detaillierte Änderungen am neuen Kardinalitätsschätzer (Cardinality Estimator, CE), der in SQL Server 2014 eingeführt wurde, sodass dies etwas seltener vorkommt als dies beim ursprünglichen CE der Fall war.

Abgesehen von der Aktualisierung auf das neueste kumulative Update und der Überprüfung, ob Optimierungskorrekturen mit 4199 aktiviert sind, können Sie vor allem versuchen, Statistiken / Indexänderungen (unter Berücksichtigung der Warnungen bei fehlenden Indizes) und Aktualisierungen vorzunehmen oder die Abfrage anders auszudrücken. Ziel ist es, einen Plan zu erstellen, der das von Ihnen gewünschte Verhalten anzeigt. Dies kann dann beispielsweise mit einer Planführung eingefroren werden.

Der anonymisierte Plan macht es schwierig, die Details zu bewerten, aber ich würde mir auch die Bitmaps genau ansehen, um festzustellen, ob sie von der Sorte 'optimiert' (Opt_Bitmap) oder Post-Optimierung (Bitmap) sind. Ich bin auch misstrauisch gegenüber den Filtern.

Wenn die Zeilenzahlen jedoch in etwa genau sind, scheint dies eine Abfrage zu sein, die von columnstore profitieren könnte. Abgesehen von den üblichen Vorteilen können Sie möglicherweise die dynamische Speicherzuweisung für Batch-Modus-Operatoren nutzen ( Trace-Flag 9389 ist möglicherweise erforderlich).

Paul White sagt GoFundMonica
quelle
7

Wenn ich auf SQL Server 2012 (11.0.6020) eine zugegebenermaßen recht einfache Testumgebung aufbaue, kann ich einen Plan mit zwei Hash-übereinstimmenden Abfragen neu erstellen, die über einen verkettet werden UNION ALL. Mein Prüfstand zeigt nicht die falsche Schätzung an, die Sie sehen. Möglicherweise handelt es sich hierbei um ein SQL Server 2014 CE-Problem.

Ich erhalte eine Schätzung von 133,785 Zeilen für eine Abfrage, die tatsächlich 280 Zeilen zurückgibt. Dies ist jedoch zu erwarten, wie wir weiter unten sehen werden:

IF OBJECT_ID('dbo.Union1') IS NOT NULL
DROP TABLE dbo.Union1;
CREATE TABLE dbo.Union1
(
    Union1_ID INT NOT NULL
        CONSTRAINT PK_Union1
        PRIMARY KEY CLUSTERED
        IDENTITY(1,1)
    , Union1_Text VARCHAR(255) NOT NULL
    , Union1_ObjectID INT NOT NULL
);

IF OBJECT_ID('dbo.Union2') IS NOT NULL
DROP TABLE dbo.Union2;
CREATE TABLE dbo.Union2
(
    Union2_ID INT NOT NULL
        CONSTRAINT PK_Union2
        PRIMARY KEY CLUSTERED
        IDENTITY(2,2)
    , Union2_Text VARCHAR(255) NOT NULL
    , Union2_ObjectID INT NOT NULL
);

INSERT INTO dbo.Union1 (Union1_Text, Union1_ObjectID)
SELECT o.name, o.object_id
FROM sys.objects o;

INSERT INTO dbo.Union2 (Union2_Text, Union2_ObjectID)
SELECT o.name, o.object_id
FROM sys.objects o;
GO

SELECT *
FROM dbo.Union1 u1
    INNER HASH JOIN sys.objects o ON u1.Union1_ObjectID = o.object_id
UNION ALL
SELECT *
FROM dbo.Union2 u2
    INNER HASH JOIN sys.objects o ON u2.Union2_ObjectID = o.object_id;

Ich denke, der Grund liegt im Fehlen von Statistiken für die beiden resultierenden Verknüpfungen, die UNIONed sind. SQL Server muss in den meisten Fällen fundierte Vermutungen über die Selektivität von Spalten anstellen, wenn statistische Daten fehlen.

Joe Sack hat eine interessante Lektüre auf , dass hier .

Für a UNION ALList es sicher zu sagen, dass wir genau die Gesamtzahl der von jeder Komponente der Union zurückgegebenen Zeilen sehen. Da SQL Server jedoch Zeilenschätzungen für die beiden Komponenten von verwendet UNION ALL, werden die geschätzten Gesamtzeilen von beiden hinzugefügt Abfragen, um die Schätzung für den Verkettungsoperator zu erhalten.

In meinem obigen Beispiel beträgt die geschätzte Anzahl von Zeilen für jeden Teil von UNION ALL66,8927, was summiert 133,785 entspricht, was wir für die geschätzte Anzahl von Zeilen für den Verkettungsoperator sehen.

Der tatsächliche Ausführungsplan für die obige Unionsabfrage sieht folgendermaßen aus:

Bildbeschreibung hier eingeben

Sie können die "geschätzte" vs "tatsächliche" Anzahl der Zeilen sehen. In meinem Fall entspricht das Hinzufügen der "geschätzten" Anzahl von Zeilen, die von den beiden Hash-Übereinstimmungsoperatoren zurückgegeben werden, genau der Menge, die vom Verkettungsoperator angezeigt wird.

Ich würde versuchen, eine Ausgabe von Trace 2363 usw. zu erhalten, wie in Paul Whites Beitrag empfohlen, den Sie in Ihrer Frage zeigen. Alternativ können Sie versuchen, OPTION (QUERYTRACEON 9481)in der Abfrage auf die Version 70 CE zurückzukehren, um zu überprüfen, ob das Problem dadurch behoben wird.

Max Vernon
quelle
1
Vielen Dank. Ich habe definitiv gesehen, dass der Grund dafür, dass es keine Statistiken für die beiden resultierenden Joins gibt, die UNIONed sind, einen großen Einfluss auf nachfolgende Joins oder Aggregationen (die nach UNION auftreten) hat. SQL 2014 handhabt dies meiner Erfahrung nach sogar besser als SQL 2012. Hier ist ein einfaches Testskript , das ich in der Vergangenheit verwendet habe: gist.github.com/anonymous/1497112d8b25ab8fb782a04569959c68 Ich würde jedoch nicht glauben, dass ein Verkettungsoperator dieselbe Art von Informationen über die Verteilung von Werten benötigt, die ein Join benötigt Könnte gebrauchen.
Geoff Patterson
Ich stimme Ihnen zu, dass für die Verkettung keine Statistiken erforderlich sind, um eine genaue Leistung zu erzielen. Es sollte einfach in der Lage sein, die eingehenden Zeilenschätzungen zuverlässig zu addieren, um einen guten Eindruck von der Anzahl der auszugebenden Zeilen zu erhalten. Wie @PaulWhite in seiner Antwort zeigt, ist das überraschenderweise nicht immer der Fall. Für mich ist das Mitnehmen hier, dass es einfach aussehen mag, aber in Wirklichkeit mag es nicht so sein. Ich bin wirklich froh, dass Sie die Frage so gestellt haben, wie Sie es getan haben. Ich wünschte nur, Sie müssten den Plan nicht anonymisieren - es wäre interessant gewesen, die tatsächliche Abfrage zu sehen.
Max Vernon