it-swarm.com.de

Wann und warum sind Datenbank-Joins teuer?

Ich recherchiere in Datenbanken und untersuche einige Einschränkungen relationaler DBs.

Ich bekomme, dass Joins von großen Tischen sehr teuer sind, bin mir aber nicht ganz sicher warum. Was muss das DBMS tun, um eine Join-Operation auszuführen? Wo liegt der Engpass?
Wie kann eine Denormalisierung helfen, diese Kosten zu überwinden? Wie helfen andere Optimierungstechniken (z. B. Indizierung)?

Persönliche Erfahrungen sind willkommen! Wenn Sie Links zu Ressourcen veröffentlichen, meiden Sie bitte Wikipedia. Ich weiß schon, wo ich das finde.

In diesem Zusammenhang wundere ich mich über die denormalisierten Ansätze, die Cloud-Service-Datenbanken wie BigTable und SimpleDB verwenden. Siehe diese Frage .

338
Rik

Denormalisieren, um die Leistung zu verbessern? Es klingt überzeugend, aber es hält kein Wasser.

Chris Date, der zusammen mit Dr. Ted Codd der ursprüngliche Befürworter des relationalen Datenmodells war, hatte keine Geduld mehr mit falsch informierten Argumenten gegen die Normalisierung und zerstörte sie systematisch mit wissenschaftlichen Methoden: Er erhielt große Datenbanken undtestingdiese Behauptungen.

Ich glaube, er hat es inRelational Database Writings 1988-1991geschrieben, aber dieses Buch wurde später in die sechste Ausgabe vonIntroduction to Database Systems aufgenommen, das istderendgültige Text zur Datenbanktheorie und -gestaltung, in seiner achten Auflage, wie ich sie schreibe und wahrscheinlich für Jahrzehnte in Druck bleiben wird. Chris Date war ein Experte auf diesem Gebiet, als die meisten von uns noch barfuß herumliefen.

Er fand, dass:

  • Einige von ihnen gelten für Sonderfälle
  • Sie alle zahlen sich für den allgemeinen Gebrauch nicht aus
  • Alle von ihnen sind für andere Sonderfälle deutlich schlechter

Es kommt alles darauf zurück, die Größe des Arbeitssets zu verringern. Joins mit richtig ausgewählten Schlüsseln mit richtig eingerichteten Indizes sind billig und nicht teuer, da sie eine signifikante Bereinigung des Ergebnissesermöglichen, bevordie Zeilen materialisiert werden.

Um das Ergebnis zu erreichen, sind Massendatenträgerlesevorgänge erforderlich, die in einer Größenordnung den teuersten Aspekt der Übung darstellen. Im Gegensatz dazu erfordert das Ausführen eines Joins logischerweise nur das Abrufen derTasten. In der Praxis werden nicht einmal die Schlüsselwerte abgerufen: Die Schlüssel-Hash-Werte werden für Verknüpfungsvergleiche verwendet, wodurch die Kosten für mehrspaltige Verknüpfungen gesenkt und die Kosten für Verknüpfungen mit Zeichenfolgenvergleichen drastisch gesenkt werden. Es passt nicht nur viel mehr in den Cache, sondern es muss auch viel weniger gelesen werden.

Darüber hinaus wählt ein guter Optimierer die restriktivste Bedingung aus und wendet sie an, bevor er einen Join ausführt, wodurch die hohe Selektivität von Joins für Indizes mit hoher Kardinalität sehr effektiv genutzt wird.

Zugegebenermaßen kann diese Art der Optimierung auch auf denormalisierte Datenbanken angewendet werden, aber die Art von Personen, dieein Schema denormalisieren möchten, denken in der Regel nicht über die Kardinalität nach, wenn (wenn) sie Richten Sie Indizes ein.

Es ist wichtig zu verstehen, dass Tabellenscans (Überprüfung jeder Zeile in einer Tabelle während der Erstellung eines Joins) in der Praxis selten sind. Ein Abfrageoptimierer wählt eine Tabellensuche nur dann aus, wenn eine oder mehrere der folgenden Bedingungen erfüllt sind.

  • Die Relation enthält weniger als 200 Zeilen (in diesem Fall ist ein Scan billiger)
  • Es gibt keine geeigneten Indizes für die Verknüpfungsspalten. (Wenn es sinnvoll ist, diese Spalten zu verknüpfen, warum sind sie dann nicht indiziert?)
  • Ein Typenzwang ist erforderlich, bevor die Spalten verglichen werden können (WTF ?! Reparieren oder nach Hause gehen) SIEHE END NOTES FÜR ADO.NET-AUSGABE
  • Eines der Argumente des Vergleichs ist ein Ausdruck (kein Index)

Die Durchführung einer Operation ist teurer als die Nichtdurchführung. Das Ausführen der Operationwrong, das Erzwingen sinnloser Datenträger-E/A und das anschließende Verwerfen der Schlacke vor dem Ausführen des Joins, den Sie wirklich benötigen, istvielteurer. Auch wenn die "falsche" Operation vorberechnet und Indizes sinnvoll angewendet wurden, bleibt ein erheblicher Nachteil bestehen. Das Denormalisieren, um einen Join vorab zu berechnen, ist - ungeachtet der damit verbundenen Aktualisierungsanomalien - eine Verpflichtung für einen bestimmten Join. Wenn Sie einenanderenBeitritt benötigen, kostet Sie diese Verpflichtunggroßen.

Wenn mich jemand daran erinnern möchte, dass sich die Welt verändert, werden Sie wahrscheinlich feststellen, dass größere Datenmengen auf grunzerer Hardware die Verbreitung von Dates Erkenntnissen nur übertreiben.

Für alle, die an Abrechnungssystemen oder Junk-Mail-Generatoren arbeiten (Schande über Sie) und empört die Hand auf die Tastatur legen, um mir mitzuteilen, dass Sie wissen, dass die Denormalisierung schneller geht. Tut mir leid, aber Sie leben in einem der Specials Fälle - insbesondere der Fall, in dem Siealleder Daten in der angegebenen Reihenfolge verarbeiten. Es ist kein allgemeiner Fall, und Siesindin Ihrer Strategie gerechtfertigt.

Sie sindnichtberechtigt, es falsch zu verallgemeinern. Weitere Informationen zur geeigneten Verwendung der Denormalisierung in Data-Warehousing-Szenarien finden Sie am Ende des Notizenabschnitts.

Ich würde auch gerne antworten

Joins sind nur kartesische Produkte mit etwas Lipgloss

Was für eine Last von Blöcken. Einschränkungen werden so früh wie möglich angewendet, am restriktivsten zuerst. Sie haben die Theorie gelesen, aber nicht verstanden. Joins werdenbehandeltals "kartesische Produkte, für die Prädikate gelten"nurvom Abfrageoptimierer. Dies ist eine symbolische Darstellung (in der Tat eine Normalisierung), um die symbolische Zerlegung zu erleichtern, sodass das Optimierungsprogramm alle entsprechenden Transformationen erstellen und nach Kosten und Selektivität sortieren kann, um den besten Abfrageplan auszuwählen.

Die einzige Möglichkeit, den Optimierer jemals dazu zu bringen, ein kartesisches Produkt zu produzieren, besteht darin, kein Prädikat anzugeben: SELECT * FROM A,B


Anmerkungen


David Aldridge bietet einige wichtige zusätzliche Informationen.

Neben Indizes und Tabellenscans gibt es in der Tat eine Vielzahl anderer Strategien, und ein moderner Optimierer wird sie alle kosten, bevor ein Ausführungsplan erstellt wird.

Ein praktischer Ratschlag: Wenn es als Fremdschlüssel verwendet werden kann, indizieren Sie es, sodass eine Indexstrategie für den Optimiererverfügbarist.

Früher war ich schlauer als der MSSQL-Optimierer. Das hat sich vor zwei Versionen geändert. Jetzt wird allgemeinmegelehrt. Im wahrsten Sinne des Wortes handelt es sich um ein Expertensystem, das die gesamte Weisheit vieler sehr kluger Leute in einem Bereich kodiert, der so weit abgeschlossen ist, dass ein regelbasiertes System effektiv ist.


"Bollocks" mögen taktlos gewesen sein. Ich werde gebeten, weniger hochmütig zu sein und daran erinnert, dass Mathe nicht lügt. Dies ist wahr, aber nicht alle Implikationen mathematischer Modelle sollten unbedingt wörtlich genommen werden. Quadratwurzeln von negativen Zahlen sind sehr praktisch, wenn Sie sorgfältig vermeiden, ihre Absurdität (Wortspiel dort) zu untersuchen, und verdammt sicher sein, dass Sie sie alle aufheben, bevor Sie versuchen, Ihre Gleichung zu interpretieren.

Der Grund, warum ich so brutal geantwortet habe, war, dass die Aussage so aussagt

Joinssindkartesische Produkte ...

Dies mag nicht das sein, was gemeint war, aber es istwas geschrieben wurde, und es ist kategorisch falsch. Ein kartesisches Produkt ist eine Beziehung. Ein Join ist eine Funktion. Genauer gesagt ist ein Join eine beziehungswertige Funktion. Mit einem leeren Prädikat wird ein kartesisches Produkt erstellt, und dies zu überprüfen, ist eine Richtigkeitsprüfung für eine Datenbankabfrage-Engine. In der Praxis schreibt jedoch niemand uneingeschränkte Verknüpfungen, da sie außerhalb eines Klassenzimmers keinen praktischen Wert haben.

Ich habe das gerufen, weil ich nicht möchte, dass Leser in die alte Falle geraten, das Modell mit dem Modellierten zu verwechseln. Ein Modell ist eine Näherung, die zur bequemen Manipulation bewusst vereinfacht wird.


Der Grenzwert für die Auswahl einer Table-Scan-Join-Strategie kann zwischen den Datenbankmodulen variieren. Es wird von einer Reihe von Implementierungsentscheidungen wie dem Füllfaktor des Baumknotens, der Größe des Schlüsselwerts und den Feinheiten des Algorithmus beeinflusst, aber im Allgemeinen hat die Hochleistungsindizierung eine Ausführungszeit vonklogn+c. Der C-Term ist ein fester Overhead, der hauptsächlich aus der Rüstzeit besteht, und die Form der Kurve bedeutet, dass Sie keine Auszahlung (im Vergleich zu einer linearen Suche) erhalten, bisnist in den Hunderten.


Manchmal ist eine Denormalisierung eine gute Idee

Denormalisierung ist eine Verpflichtung zu einer bestimmten Join-Strategie. Wie bereits erwähnt, stört diesandereJoin-Strategien. Wenn Sie jedoch über genügend Speicherplatz, vorhersehbare Zugriffsmuster und die Tendenz verfügen, einen Großteil oder alles zu verarbeiten, kann sich die Vorausberechnung eines Joins sehr lohnen.

Sie können auch die Zugriffspfade ermitteln, die Ihre Operation normalerweise verwendet, und alle Verknüpfungen für diese Zugriffspfade vorberechnen. Dies ist die Voraussetzung für Data Warehouses, oder zumindest, wenn sie von Personen erstellt werden, die wissen, warum sie das tun, was sie tun, und dies nicht nur, um die Einhaltung von Schlagworten zu gewährleisten.

Ein ordnungsgemäß entworfenes Data Warehouse wird in regelmäßigen Abständen durch eine Massenumwandlung aus einem normalisierten Transaktionsverarbeitungssystem erstellt. Diese Trennung der Betriebs- und Berichtsdatenbanken hat den sehr wünschenswerten Effekt, dass der Konflikt zwischen OLTP und OLAP (Online-Transaktionsverarbeitung, dh Dateneingabe, und Online-Analyse) beseitigt wird Verarbeitung, dh Berichterstattung).

Ein wichtiger Punkt hierbei ist, dass das Data Warehouse neben den regelmäßigen Aktualisierungenread onlyist. Dadurch wird die Frage nach Aktualisierungsanomalien aufgeworfen.

Machen Sie nicht den Fehler, Ihre OLTP) -Datenbank (die Datenbank, in der Daten eingegeben werden) zu denormalisieren. Dies ist möglicherweise schneller für Abrechnungsläufe, aber wenn Sie dies tun, treten Aktualisierungsanomalien auf kann Reader's Digest nicht mehr senden?

Speicherplatz ist heutzutage billig, also hau ab. Denormalisierung ist jedoch nur ein Teil der Geschichte von Data Warehouses. Viel größere Leistungssteigerungen ergeben sich aus vorberechneten aufsummierten Werten: monatliche Summen, so etwas. Es gehtimmerdarum, den Arbeitssatz zu verkleinern.


ADO.NET-Problem mit Typenkonflikten

Angenommen, Sie haben eine SQL Server-Tabelle mit einer indizierten Spalte vom Typ varchar und übergeben mit AddWithValue einen Parameter, der eine Abfrage für diese Spalte einschränkt. C # -Strings sind Unicode, daher ist der abgeleitete Parametertyp NVARCHAR, der nicht mit VARCHAR übereinstimmt.

VARCHAR zu NVARCHAR ist eine erweiterte Konvertierung, die implizit erfolgt. Verabschieden Sie sich jedoch von der Indizierung und finden Sie heraus, warum.


"Count the disk hits" (Rick James)

Wenn alles im RAM zwischengespeichert ist, sind JOINs ziemlich billig. Das heißt, die Normalisierung hat nicht vielPerformance-Einbußen.

Wenn ein "normalisiertes" Schema dazu führt, dass JOINs häufig auf den Datenträger trifft, das entsprechende "denormalisierte" Schema jedoch nicht auf den Datenträger trifft, gewinnt die Denormalisierung einen Leistungswettbewerb.

Kommentar des ursprünglichen Autors: Moderne Datenbank-Engines können Zugriffssequenzen sehr gut organisieren, um Cache-Fehler während Verknüpfungsvorgängen zu minimieren. Obgleich dies zutrifft, könnte dies falsch sein, da dies impliziert, dass Verknüpfungen bei großen Datenmengen notwendigerweise problematisch sind. Dies würde bei unerfahrenen Entwicklern zu schlechten Entscheidungen führen.

454
Peter Wone

Was die meisten Kommentatoren nicht bemerken, ist das breite Spektrum der in einem komplexen RDBMS verfügbaren Join-Methoden, und die Denormalisierer beschönigen stets die höheren Kosten für die Pflege denormalisierter Daten. Nicht jeder Join basiert auf Indizes, und Datenbanken verfügen über zahlreiche optimierte Algorithmen und Methoden für den Join, mit denen die Join-Kosten gesenkt werden sollen.

In jedem Fall hängen die Kosten eines Joins von seinem Typ und einigen anderen Faktoren ab. Es muss überhaupt nicht teuer sein - einige Beispiele.

  • Ein Hash-Join, bei dem Massendaten gleichgesetzt werden, ist in der Tat sehr billig, und die Kosten werden nur dann erheblich, wenn die Hash-Tabelle nicht im Speicher zwischengespeichert werden kann. Kein Index erforderlich. Eine gleichmäßige Partitionierung zwischen den verbundenen Datensätzen kann eine große Hilfe sein.
  • Die Kosten eines Sort-Merge-Joins werden eher von den Kosten der Sortierung als von der Zusammenführung bestimmt. Eine indexbasierte Zugriffsmethode kann die Kosten der Sortierung praktisch eliminieren.
  • Die Kosten für einen Join mit verschachtelten Schleifen für einen Index werden durch die Höhe des B-Tree-Index und den Zugriff auf den Tabellenblock selbst bestimmt. Es ist schnell, aber nicht für Massenverbindungen geeignet.
  • Ein auf einem Cluster basierender Join mit verschachtelten Schleifen ist viel billiger, da pro Join-Zeile weniger logische E/A erforderlich sind. Befinden sich die verknüpften Tabellen im selben Cluster, wird der Join durch das Zusammenfassen verknüpfter Zeilen sehr kostengünstig.

Datenbanken sind so konzipiert, dass sie sich verbinden lassen, und sie sind sehr flexibel und im Allgemeinen sehr performant, es sei denn, der Verbindungsmechanismus stimmt nicht.

44
David Aldridge

Ich denke, die ganze Frage basiert auf einer falschen Prämisse. Joins auf großen Tabellen sind nicht unbedingt teuer. Tatsächlich ist Joins effizient auszuführen einer der Hauptgründe, warum relationale Datenbanken existieren überhaupt. Verknüpfungen in großen Mengen sind oft teuer, aber sehr selten möchten Sie den gesamten Inhalt der großen Tabelle A mit dem gesamten Inhalt der großen Tabelle B verknüpfen. Stattdessen schreiben Sie die Abfrage so, dass nur die wichtigen Zeilen jeder Tabelle verwendet werden und die tatsächliche Menge, die vom Join beibehalten wird, kleiner bleibt.

Darüber hinaus verfügen Sie über die von Peter Wone genannten Effizienzvorteile, sodass nur die wichtigen Teile jedes Datensatzes gespeichert werden müssen, bis die endgültige Ergebnismenge vorliegt. Bei großen Abfragen mit vielen Verknüpfungen möchten Sie in der Regel mit den kleineren Tabellensätzen beginnen und sich zu den großen hocharbeiten, damit der im Speicher gespeicherte Satz so klein wie möglich bleibt.

Bei richtiger Ausführung sind Verknüpfungen im Allgemeinen die beste Möglichkeit , große Datenmengen zu vergleichen, zu kombinieren oder zu filtern.

27
Joel Coehoorn

Der Engpass ist so ziemlich immer Festplatten-E/A und insbesondere - zufällige Festplatten-E/A (im Vergleich dazu sind sequenzielle Lesevorgänge relativ schnell und können mit Vorauslesestrategien zwischengespeichert werden).

Joins can Zufällige Suchanfragen erhöhen - wenn Sie herumspringen und kleine Teile eines großen Tisches lesen. Abfrageoptimierer suchen danach und wandeln es in einen sequentiellen Tabellenscan um (wobei die nicht benötigten Zeilen verworfen werden), wenn sie dies für besser halten.

Eine einzelne denormalisierte Tabelle weist ein ähnliches Problem auf: Die Zeilen sind groß und passen daher weniger auf eine einzelne Datenseite. Wenn Sie Zeilen benötigen, die weit voneinander entfernt sind (und die große Zeilengröße sie weiter voneinander entfernt), haben Sie mehr zufällige E/A-Vorgänge. Auch hier kann ein Tabellenscan erzwungen werden, um dies zu vermeiden. Diesmal muss Ihr Tabellenscan jedoch aufgrund der großen Zeilengröße mehr Daten lesen. Fügen Sie noch die Tatsache hinzu, dass Sie Daten kopieren von einem Ort zu mehreren Orten, und das RDBMS hat so viel mehr zu lesen (und zu zwischenspeichern).

Mit 2 Tabellen erhalten Sie auch 2 Clustered-Indizes - und können im Allgemeinen mehr indizieren (aufgrund des geringeren Einfüge-/Aktualisierungsaufwands), wodurch Sie die Leistung drastisch steigern können (vor allem, weil die Indizes (relativ) klein sind und schnell von der Festplatte gelesen werden können (oder billig zu cachen), und verringern Sie die Anzahl der Tabellenzeilen, die Sie von der Festplatte lesen müssen).

Der einzige Mehraufwand bei einem Join besteht darin, die übereinstimmenden Zeilen zu ermitteln. Sql Server verwendet 3 verschiedene Arten von Joins, hauptsächlich basierend auf der Größe des Datasets, um passende Zeilen zu finden. Wenn das Optimierungsprogramm den falschen Verknüpfungstyp auswählt (aufgrund ungenauer Statistiken, unzureichender Indizes oder nur eines Optimierungsfehlers oder eines Edge-Falls), kann sich dies drastisch auf die Abfragezeiten auswirken.

  • Ein Loop-Join ist für (mindestens 1) kleine Datenmengen sehr günstig.
  • Für einen Merge-Join müssen zuerst beide Datasets sortiert werden. Wenn Sie sich jedoch einer indizierten Spalte anschließen, ist der Index bereits sortiert und es sind keine weiteren Arbeiten erforderlich. Andernfalls entsteht beim Sortieren ein gewisser CPU- und Speicheraufwand.
  • Der Hash-Join benötigt sowohl Speicher (um die Hash-Tabelle zu speichern) als auch CPU (um den Hash zu erstellen). Auch dies ist relativ schnell in Bezug auf die Festplatten-E/A. Allerdings, wenn nicht genug RAM zum Speichern der Hashtabelle vorhanden ist, verwendet Sql Server tempdb zum Speichern von Teilen der Hashtabelle und der gefundenen Zeilen und verarbeitet dann nur Teile von Die Hash-Tabelle zu einer Zeit. Wie bei allen Dingen Festplatte, ist dies ziemlich langsam.

Im optimalen Fall verursachen diese keine Festplatten-E/A - und sind daher aus Sicht der Leistung vernachlässigbar.

Alles in allem sollte es im schlimmsten Fall tatsächlich schneller sein, die gleiche Menge an logischen Daten aus x verbundenen Tabellen zu lesen, wie dies aufgrund der kleineren Plattenlesevorgänge aus einer einzelnen denormalisierten Tabelle der Fall ist. Um die gleiche Menge an physischen Daten zu lesen, kann es zu geringfügigem Overhead kommen.

Da die Abfragezeit in der Regel von den E/A-Kosten bestimmt wird und sich die Größe Ihrer Daten bei der Denormalisierung nicht ändert (abzüglich eines sehr geringen Zeilenaufwands), bietet das Zusammenführen von Tabellen keine enormen Vorteile. Die Art der Denormalisierung, mit der die Leistung tendenziell gesteigert wird (IME), speichert berechnete Werte im Cache, anstatt die 10.000 Zeilen zu lesen, die zu ihrer Berechnung erforderlich sind.

11
Mark Brackett

Die Reihenfolge, in der Sie die Tabellen verbinden, ist äußerst wichtig. Wenn Sie über zwei Datensätze verfügen, versuchen Sie, die Abfrage so zu erstellen, dass der kleinste zuerst verwendet wird, um die Datenmenge zu verringern, mit der die Abfrage arbeiten muss.

Für einige Datenbanken spielt es keine Rolle, zum Beispiel kennt MS SQL die meiste Zeit die richtige Verknüpfungsreihenfolge. Für einige (wie IBM Informix) macht die Reihenfolge den Unterschied.

4
Ilya Kochetov

Die Entscheidung, ob eine Denormalisierung oder eine Normalisierung durchgeführt werden soll, ist in Anbetracht der Komplexitätsklasse des Joins recht einfach. Zum Beispiel tendiere ich dazu, meine Datenbanken mit Normalisierung zu entwerfen, wenn die Abfragen O (k log n) sind, wobei k relativ zur gewünschten Ausgabegröße ist.

Eine einfache Methode zum Denormalisieren und Optimieren der Leistung besteht darin, zu überlegen, wie sich Änderungen an Ihrer Normalisierungsstruktur auf Ihre denormalisierte Struktur auswirken. Dies kann jedoch problematisch sein, da möglicherweise Transaktionslogik erforderlich ist, um an einer denormalisierten Struktur zu arbeiten.

Die Debatte um Normalisierung und Denormalisierung wird nicht enden, da die Probleme groß sind. Es gibt viele Probleme, bei denen die natürliche Lösung beide Ansätze erfordert.

Im Allgemeinen habe ich immer eine normalisierte Struktur und denormalisierte Caches gespeichert, die wiederhergestellt werden können. Letztendlich retten diese Caches meinen Arsch, um die zukünftigen Normalisierungsprobleme zu lösen.

0
MathGladiator