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_detail
1,5 Milliarden Zeilen.
Diese Tabelle dwh.fac_sale_detail
wird basierend auf einer ihrer aufgerufenen Spalten partitioniert TradingDateKey1
. Es speichert tatsächlich Daten im Format JJJJMMTT, ist jedoch vom INT
Datentyp.
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 FactSalesDetail
Tabelle umfasst derzeit etwa 1,5 Milliarden Zeilen und ist derzeit TradingDate
in 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:
quelle
Antworten:
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:
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 PARTITION
und 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_Date
einer komplizierten Logik anzuschließencast(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_Date
und 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_Date
einer 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:In diesem Fall enthält die
Dim_Date
Tabelle 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.
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
Sort
und ausgeführtStream Aggregate
wird, 324 Millionen Zeilen ergibt. Es ergibt jedoch nur 643.000 Zeilen.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 einesSORT GROUP
(Sort-Stream) verwenden, um IhreGROUP BY
Klausel 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 GROUP
ist viel einfacher als das Verwenden eines Verknüpfungshinweises, das VerwendenFORCE ORDER
oder 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:
Sort
Operator (wie oben beschrieben); Es ist wirklich der einzige Operator, der in Ihrer Abfrage einen erheblichen Speicherbedarf verbrauchtquelle
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.
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.
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.
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.
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.
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:
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?
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?
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.
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.
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.
quelle