Optimierung der Star Join-Abfrage - Partitionierung ändern, Spaltenspeicher verwenden?


7

Ich versuche, den bestmöglichen Weg zu finden, um die Leistung einer von meinem Kunden gestellten Abfrage zu verbessern. Es enthält einige Tabellen, die verbunden sind, und eine Tabelle heißt dwh.fac_sale_detail1,5 Milliarden Zeilen.

Diese Tabelle dwh.fac_sale_detailwird basierend auf einer ihrer aufgerufenen Spalten partitioniert TradingDateKey1. Es speichert tatsächlich Daten im Format JJJJMMTT, ist jedoch vom INTDatentyp.

Dies hat TradingDateKeys von 2005 bis 2015, aber die Partitionen werden nur bis zum Jahr 2014 erstellt.

Einer der Jungs in einem anderen Team hat Folgendes empfohlen, und ich versuche, seinem Rat zu folgen, aber ich bin neu im Erstellen oder Ändern von Partitionen und weiß nicht, ob dies tatsächlich einen Unterschied für die Abfrageleistung bedeutet:

In seinen eigenen Worten sagte er: " Die FactSalesDetailTabelle umfasst derzeit etwa 1,5 Milliarden Zeilen und ist derzeit TradingDatein 10 Partitionen pro Jahr mit etwa 150 Millionen Zeilen pro Partition unterteilt. Es wäre eine gute Idee, das letzte Jahr weiter in monatliche Partitionen zu unterteilen und wenden Sie einen Columnstore-Index auf alle Partitionen an. Das Anwenden des Index auf jede Partition ist einmalig und Sie sollten künftig nur den Index für die aktuelle Partition pflegen müssen . "

Hier ist der Abfrageplan für die Abfrage, die ich optimieren möchte.

Bitte beachten Sie auch die beigefügten Screenshots zum besseren Verständnis:

Geben Sie hier die Bildbeschreibung ein

Geben Sie hier die Bildbeschreibung ein


Auf welcher Version von SQL Server befinden Sie sich? Wird es weitere Indizes für die monatlichen Partitionen geben? Wenn ja, was sind sie?
James Anderson

Ich stimme dem Partitionierungsansatz im Allgemeinen zu. Was genau fragen Sie? Informationen zu einer Partitionierungsstrategie oder zur tatsächlichen Partitionierung in SQL? Woher kommt ssis? (Ich habe festgestellt, dass Ihr Q mit ssis gekennzeichnet ist.)
Siebzigster

2
Konzentrieren Sie sich hauptsächlich darauf, nur die eine Abfrage zu optimieren, die Sie erwähnen? Wenn ja, veröffentlichen Sie bitte den tatsächlichen Ausführungsplan der Abfrage. Sie können den SQL Sentry Plan Explorer verwenden, um den Plan bei Bedarf zu anonymisieren. Eine weitere Partitionierung kann die Leistung verbessern oder die Leistung erheblich beeinträchtigen. Es hängt alles davon ab, wie Sie die Daten abfragen. In ähnlicher Weise kann der Spaltenspeicher die Leistung beeinträchtigen oder beeinträchtigen (insbesondere in SQL 2012, wenn auf die Ausführung im Zeilenmodus zurückgegriffen wird).
Geoff Patterson

1
Ihr tatsächlicher Abfrageplan wird hier hilfreich sein. Es kann sein, dass Ihre Abfragen niemals eine Partitionseliminierung durchführen
billinkc

In welcher Form haben Sie Ihren Abfrageplan?
Dekso

Antworten:


11

Vielen Dank, dass Sie den Abfrageplan hinzugefügt haben. es ist sehr informativ. Ich habe eine Reihe von Empfehlungen, die auf dem Abfrageplan basieren, aber zunächst eine Einschränkung: Nehmen Sie nicht nur das, was ich sage, und nehmen Sie an, dass es korrekt ist, probieren Sie es zuerst aus (idealerweise in Ihrer Testumgebung) und stellen Sie sicher, dass Sie verstehen, warum die Änderungen funktionieren oder verbessern Sie Ihre Anfrage nicht!

Der Abfrageplan: eine Übersicht

Aus diesem Abfrageplan (sowie dem entsprechenden XML) können wir sofort einige nützliche Informationen ersehen:

  • Sie befinden sich in SQL 2012
  • Dies ist eine klassische Star-Join-Abfrage, und Sie profitieren von der In-Row-Bitmap-Filteroptimierung , die in SQL 2008 für solche Pläne hinzugefügt wurde
  • Die Faktentabelle enthält ungefähr 1,5 Milliarden Zeilen, und etwas mehr als 500 Millionen dieser Zeilen stimmen mit den Dimensionsfiltern überein
  • Die Abfrage fordert 72 GB Arbeitsspeicher an, erhält jedoch nur 12 GB Arbeitsspeicher (vermutlich sind 12 GB das Maximum, das für eine bestimmte Abfrage gewährt wird, was bedeutet, dass Ihr Computer wahrscheinlich über ~ 64 GB Arbeitsspeicher verfügt).
  • SQL Server führt ein Sortierstromaggregat durch, das 500 Millionen Zeilen auf nur 600.000 Zeilen reduziert. Die Sortierung überschreitet die Speicherzuweisung und wird auf Tempdb übertragen
  • Wir haben Warnungen für planbeeinflussende Konvertierungen aufgrund expliziter und impliziter Konvertierungen in Ihrer Abfrage
  • Die Abfrage verwendet 32 ​​Threads, aber die anfängliche Suche in Ihrer Faktentabelle weist einen enormen Thread-Versatz auf. Nur 2 der 32 Threads erledigen die ganze Arbeit. (In den folgenden Schritten des Abfrageplans ist die Arbeit jedoch ausgewogener.)

Geben Sie hier die Bildbeschreibung ein

Optimierung: Columnstore oder nicht

Dies ist eine schwierige Frage, aber insgesamt würde ich Columnstore in diesem Fall nicht empfehlen. Der Hauptgrund ist, dass Sie sich in SQL 2012 befinden. Wenn Sie also ein Upgrade auf SQL 2014 durchführen können, lohnt es sich möglicherweise, Columnstore auszuprobieren.

Im Allgemeinen ist Ihre Abfrage der Typ, für den der Spaltenspeicher entwickelt wurde, und kann von der reduzierten E / A des Spaltenspeichers und der höheren CPU-Effizienz des Stapelmodus erheblich profitieren.

Die Einschränkungen des Spaltenspeichers in SQL 2012 sind jedoch einfach zu groß, und das Tempdb-Überlaufverhalten , bei dem SQL Server durch einen Überlauf den Batch-Modus vollständig aufgibt , kann eine verheerende Strafe sein, die bei den großen Zeilenmengen auftreten kann arbeiten mit. Wenn Sie sich für Columnstore unter SQL 2012 entscheiden, sollten Sie darauf vorbereitet sein, alle Ihre Abfragen sehr genau zu bearbeiten und sicherzustellen, dass der Stapelmodus immer verwendet werden kann.

Optimierung: mehr Partitionen?

Ich denke nicht, dass mehr Partitionen dieser speziellen Abfrage helfen werden. Sie können es natürlich gerne ausprobieren, aber denken Sie daran, dass die Partitionierung in erster Linie eine Datenverwaltungsfunktion ist (die Möglichkeit, neue Daten in Ihren ETL-Prozessen über SWITCH PARTITIONund keine Leistungsfunktion auszutauschen. In einigen Fällen kann dies natürlich die Leistung verbessern.) In ähnlicher Weise kann dies jedoch die Leistung anderer beeinträchtigen (z. B. viele Singleton-Suchvorgänge, die jetzt einmal pro Partition ausgeführt werden müssen).

Wenn Sie sich für Columnstore entscheiden, ist das Laden Ihrer Daten zur besseren Segmenteliminierung meiner Meinung nach wichtiger als das Partitionieren. Idealerweise möchten Sie wahrscheinlich so viele Zeilen in jeder Partition wie möglich, um vollständige Spaltenspeichersegmente und hohe Komprimierungsraten zu erhalten.

Optimierung: Verbesserung der Kardinalitätsschätzungen

Da Sie eine große Faktentabelle und eine Handvoll sehr kleiner (Hunderte oder Tausende von Zeilen) Zeilen aus jeder Dimensionstabelle haben, würde ich einen Ansatz empfehlen, bei dem Sie explizit eine temporäre Tabelle erstellen, die nur die Dimensionszeilen enthält, die Sie verwenden möchten . Anstatt sich beispielsweise Dim_Dateeiner komplizierten Logik anzuschließen cast(right(ALHDWH.dwh.Dim_Date.Financial_Year,4) as int) IN ( 2015, 2014, 2013, 2012, 2011 ), sollten Sie eine Abfrage vor der Verarbeitung schreiben, um nur die Zeilen zu extrahieren, die Ihnen wichtig sind, Dim_Dateund diesen Zeilen die entsprechende PK hinzuzufügen.

Auf diese Weise kann SQL Server Statistiken nur für die Zeilen erstellen, die Sie tatsächlich verwenden. Dies kann zu besseren Kardinalitätsschätzungen im gesamten Plan führen. Da diese Vorverarbeitung im Vergleich zur Gesamtkomplexität der Abfragen einen so geringen Arbeitsaufwand darstellt, würde ich diese Option wärmstens empfehlen.

Optimierung: Reduzierung des Fadenversatzes

Es ist wahrscheinlich, dass das Extrahieren der Daten aus Dim_Dateeiner eigenen Tabelle und das Hinzufügen eines Primärschlüssels zu dieser Tabelle auch dazu beitragen würde, den Thread-Versatz zu verringern (ein Ungleichgewicht der Arbeit zwischen den Threads). Hier ist ein Bild, das zeigt, warum:

Geben Sie hier die Bildbeschreibung ein

In diesem Fall enthält die Dim_DateTabelle 22.000 Zeilen. SQL Server schätzt, dass Sie 7.700 dieser Zeilen verwenden werden, und Sie haben tatsächlich nur 1.827 dieser Zeilen verwendet.

Da SQL Server Statistiken verwendet, um Threads Zeilenbereiche zuzuweisen, sind die schlechten Kardinalitätsschätzungen in diesem Fall wahrscheinlich die Hauptursache für die sehr schlechte Verteilung der Zeilen.

Thread-Versatz in 1.872 Zeilen mag nicht viel ausmachen, aber der schmerzliche Punkt ist, dass dies dann zur Suche in Ihrer 1,5-Milliarden-Zeilen-Faktentabelle führt, in der 30 Threads im Leerlauf sitzen, während 600 Millionen Zeilen von 2 Threads verarbeitet werden.

Geben Sie hier die Bildbeschreibung ein

Optimierung: Beseitigung der Art Verschüttung

Ein weiterer Bereich, auf den ich mich konzentrieren würde, ist die Sortierung. Ich denke, dass das Hauptproblem in diesem Fall schlechte Kardinalitätsschätzungen sind. Wie wir unten sehen können, geht SQL Server davon aus, dass die Gruppierungsoperation, die durch die Kombination von a Sortund ausgeführt Stream Aggregatewird, 324 Millionen Zeilen ergibt. Es ergibt jedoch nur 643.000 Zeilen.

Geben Sie hier die Bildbeschreibung ein

Wenn SQL Server wüsste, dass so wenige Zeilen aus dieser Gruppierung hervorgehen würden, würde es mit ziemlicher Sicherheit ein HASH GROUP(Hash-Aggregat) anstelle eines SORT GROUP(Sort-Stream) verwenden, um Ihre GROUP BYKlausel zu implementieren .

Es ist möglich, dass sich dies von selbst behebt, wenn Sie einige der anderen oben genannten Änderungen vornehmen, um die Kardinalitätsschätzungen zu verbessern. Wenn dies nicht der Fall ist, können Sie versuchen, den OPTION (HASH GROUP) Abfragehinweis zu verwenden, um SQL Server dazu zu zwingen. Auf diese Weise können Sie das Ausmaß der Verbesserung bewerten und entscheiden, ob Sie den Abfragehinweis in der Produktion verwenden möchten oder nicht. Bei Abfragehinweisen bin ich im Allgemeinen vorsichtig, aber das Festlegen von "Nur" HASH GROUPist viel einfacher als das Verwenden eines Verknüpfungshinweises, das Verwenden FORCE ORDERoder anderweitige Entfernen eines zu großen Teils der Kontrolle aus den Händen des Abfrageoptimierers.

Optimierung: Speichergewährung

Ein letztes potenzielles Problem war, dass SQL Server schätzte, dass die Abfrage 72 GB Speicher verwenden möchte, Ihr Server jedoch nicht so viel Speicher für die Abfrage bereitstellen konnte. Obwohl es technisch gesehen richtig ist, dass das Hinzufügen von mehr Speicher zum Server hilfreich ist, gibt es meines Erachtens mindestens ein paar andere Möglichkeiten, um dieses Problem anzugehen:

  • Entfernen Sie den SortOperator (wie oben beschrieben); Es ist wirklich der einzige Operator, der in Ihrer Abfrage einen erheblichen Speicherbedarf verbraucht
  • Teilen Sie Ihre Anfrage in mehrere Stapel auf. Es kann beispielsweise vorkommen, dass Sie die Abfrage einmal pro Partition ausführen können. Dies könnte die Größe der Sortierung verringern, sie im Speicher behalten und möglicherweise die Leistung erheblich verbessern. Ein Nebeneffekt könnte sein, dass Sie Threads möglicherweise besser nutzen, wenn Sie nur auf eine Partition zugreifen, da dies in einigen Fällen die Art und Weise beeinflusst, wie SQL Server Partitionen Threads zuweist.

Vielen Dank Geoff, für Ihre Zeit und für Ihre prompten Antworten. Ich werde dies in der DEV-Umgebung versuchen und hoffentlich die Leistung verbessern. Aber Geoff, eine Sache, die ich nicht ganz verstanden habe, wie ich die Art loswerden kann verschütten. Bitte lassen Sie mich wissen, was mit der Art verschüttet werden kann.
Deepak

1
@Deepak, ich meine, Sie können den Text "OPTION (HASH GROUP)" am Ende Ihrer Abfrage hinzufügen, sehen, wie sich der geschätzte Abfrageplan ändert (die Sortierung sollte verschwinden) und dann die Abfrage mit diesem Hinweis in Ihrem ausführen DEV-Umgebung. Da SQL Server die Anzahl der Zeilen falsch einschätzt, wird das Sortier-Stream-Aggregat anstelle des Hash-Aggregats gewählt (was für diesen speziellen Plan eine weitaus bessere Wahl wäre). Dieser Abfragehinweis zwingt SQL Server, das Hash-Aggregat zu verwenden.
Geoff Patterson

Danke Geoff, ich habe dich. <br> Du warst eine große Hilfe für mich und ein glücklicher Wochenendkamerad!.
Deepak

Hallo Geoff, vielen Dank, die Abfrage wurde von 1 Stunde auf 32 Minuten reduziert: 32 Minuten. Die einzige Änderung, die ich vorgenommen habe, um die Option [HASH GROUP] am Ende der Abfrage hinzuzufügen.
Deepak

1

Das Optimieren von STAR-Abfragen entspricht in vielerlei Hinsicht dem Optimieren anderer Abfragestile. Zusätzlich enthalten STAR-Abfragen einige spezielle Überlegungen. Es kann sich für Sie lohnen, einige der wesentlichen Punkte und Grundlagen noch einmal zu überdenken.

  1. PRÄZISIONSSTIL vs. LAGERSTIL. Jede Abfrage STAR oder auf andere Weise kann als PRECISION- oder WAREHOUSE-Stil klassifiziert werden. Damit meinen wir, dass entweder eine große Anzahl von Zeilen oder eine kleine Anzahl von Zeilen zurückgegeben wird. Groß und Klein werden nach dem Filtern am häufigsten als% der Zeilen aus einer Tabelle definiert. In diesem Zusammenhang wird häufig die 2% -Regel angegeben, da dieser Prozentsatz sowohl mathematisch fundiert als auch in der Praxis als Richtlinie für die meisten Abfragesituationen erfolgreich ist beim Definieren des Abfragestils. Dies alles bedeutet, dass wenn Sie <2% der Zeilen in einer Tabelle möchten, ein Index möglicherweise besser zum Abrufen dieser Zeilen geeignet ist. Wenn Sie jedoch> 2% der Zeilen in einer Tabelle möchten, ist ein Tabellenscan wahrscheinlich besser. Ja, es gibt Randfälle und Variationen für bestimmte Datenfehler.

  2. Angesichts der Idee einer "2% RULE%" soll eine echte STAR-Abfrage <2% der Zeilen in ihrer Faktentabelle zurückgeben. Eine von Dimensionen umgebene und in BITMAP-Indizes abgedeckte Faktentabelle impliziert nicht, dass eine Abfrage für dieses Design eine STAR-Abfrage ist. Eine "STAR-Abfrage", die> 2% der Zeilen aus ihrer Faktentabelle zurückgibt, ist keine langsame STAR-Abfrage, sondern eine DATA MINING-Operation mit dem falschen Datenbankdesign. Zusätzlich wurden BITMAP-Indizes speziell für das STAR Query-Optimierungsproblem erstellt. Obwohl für eine STAR-Abfrage kein bestimmter einzelner Index <2% der Zeilen identifizieren muss, sollte das resultierende zurückgegebene Rowset <2% der Zeilen in Ihrer Faktentabelle sein, nachdem alle durchsuchten Indizes über den Schritt BITMAP MERGE kombiniert wurden. Dies wird in RAW-Zeilen aus der Faktentabelle definiert, nicht in aggregierten Zeilen. Andernfalls ist es in den meisten Fällen besser, einfach die FACT-Tabelle zu scannen und überhaupt keine Zeit mit Indizes zu verschwenden. Somit wird sogar eine STAR-Abfrage im Optimierungsbereich vom Konzept des PRECISION vs. WAREHOUSE-Stils dominiert.

  3. Partitionierung für Leistung. Die Partitionierung aus Sicht der Leistung hat zwei Hauptdienstprogramme. Das erste ist das Bereinigen von Partitionen. Bei Abfragen, deren Prädikate eine Filterung nach Partitionsschlüsseln ermöglichen, kann ein Optimierer ganze Partitionen überspringen, anstatt sie zu scannen. Dies reduziert die E / A. Die zweite Verwendung besteht darin, parallele Verknüpfungen zu aktivieren, die als Partitionspaare ausgeführt werden. Wenn zwei Tabellen in einer Abfrage über den Verknüpfungsschlüssel einer Abfrage gleich verteilt sind, kann diese Abfrage die beiden Tabellen parallel verknüpfen, indem nur übereinstimmende Partitionspaare verwendet werden. Dies macht den Join hoch skalierbar und reduziert den Speicherbedarf erheblich. Auch hier ist der Schlüssel eine gleichmäßige Partitionierung über die Join-Spalten.

  4. Säulenspeicherung und Leistung. Ein kolumnarer Datenspeicher bietet Leistung auch auf zwei grundlegende Arten. Erstens ist die Komprimierung. Diese Speicherstrategie sammelt ähnliche Daten. Somit können insbesondere wenn der Schritt des Vorsortierens ausgeführt wird, große Kompressionsverhältnisse in einem Spaltendatenspeicher erreicht werden. Diese Komprimierung kann unter den richtigen Bedingungen die E / A-Kosten erheblich senken. Zweitens versucht diese Speicherstrategie, die Tatsache auszunutzen, dass die meisten Abfragen nicht alle Spalten erfordern. Ein spaltenartiger Datenspeicher eröffnet somit die Möglichkeit, Spalten zu überspringen, die für eine Abfrage nicht erforderlich sind. Dies kann wiederum die E / A-Kosten senken. Wenn für eine Abfrage <5% der Spalten in einer Tabelle erforderlich sind, kann die Leistungssteigerung durch die Spaltenprojektion in der Regel erheblich sein.

  5. PRE-Aggregation. Übersichtstabellen spielen immer noch eine wichtige Rolle für die Leistung. Es ist immer schneller, bereits summierte Zeilen abzurufen, als die Details zu übernehmen und sie jedes Mal zu summieren, wenn Sie sie benötigen. Im STAR-Abfragebereich bedeutet dies normalerweise, dass Abfragen überwacht werden, um festzustellen, welche Dimensionen am beliebtesten sind, die in Scheiben geschnitten / gewürfelt / hierarchisch durchlaufen werden. Diese sind gute Kandidaten für Übersichtstabellen, vorausgesetzt, Ihr Datenbanksystem kann diese Zusammenfassungsobjekte bei Bedarf transparent identifizieren.

Stellen Sie sich vor diesem Hintergrund zunächst einige Fragen:

  1. hast du das richtige design Ist Ihre Abfrage wirklich eine STAR-Abfrage, die letztendlich <2% der Zeilen aus der Faktentabelle neu abstimmt? Oder versuchen Sie etwas Großes gegen das falsche Speicherdesign zu tun?

  2. Prädikate Ihre Abfrage Ihrem Partitionierungsschema? Wenn ja, nutzen sie die Partitionierung aus (tatsächlich bereinigen)? Wenn ja, sind Sie dann möglicherweise ein Kandidat für Parallelität zwischen einem der Joins?

  3. Wie viel Prozent der Spalten suchen Sie? Können Sie mithilfe der Komprimierung eine Reduzierung des Speicherplatzbedarfs um eine Größenordnung erreichen und so möglicherweise die Abfragezeit durch Reduzierung der E / A beschleunigen? Suchen Sie nach <5% der Spalten in Ihrer Tabelle und können daher von einem Spaltenspeicher profitieren, um unerwünschte Teile der Tabelle zu überspringen.

  4. Wie viel Ihrer Abfragekosten entfällt auf E / A und wie viel auf Verknüpfungen / Aggregationen / Sortierungen? Wo Ihre Kosten liegen, wird Ihre Auswahl an Leistungsmerkmalen bestimmen.

  5. Gibt es bestimmte Aggregationen, die, wenn sie existieren würden, Ihr Abfrageleistungsprofil dramatisch verändern würden?

In Bezug auf den Rat Ihres Freundes sollten Sie um weitere Erläuterungen bitten. Dort gibt es eindeutig viele Annahmen. 1. dass ältere Partitionen schreibgeschützt sind. 2. dass Ihre Abfrage bestimmte Monate abruft, anstatt Jahre zu überschreiten (vergleichen Sie beispielsweise zwei Viertel).

Bedenken Sie schließlich, dass, wenn die Partitionierung und der Spaltenspeicher Ihres Freundes wichtige Hilfsmittel sein könnten, dies darauf hindeutet, dass Ihre Abfrage keine STAR-Abfrage ist, da BITMAP INDEXING der Hauptleistungstreiber der Abfrage und ihrer Partitionierung und Spaltenspeicherung ist würde sehr wenig für die Gesamtleistung bedeuten. Daher sollte es offensichtlich sein, dass Sie zuerst die Anforderungen der Abfrage prüfen und sie dem richtigen Speicherdesign zuordnen müssen.

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.