Viele Spalten gegen wenige Tabellen - leistungsmäßig


12

Ja, mir ist bewusst, dass die Datennormalisierung meine Priorität sein sollte (so wie sie ist).

  1. Ich habe eine Tabelle mit 65 Spalten Speicherung von Fahrzeugdaten mit Spalten: used_vehicle, color, doors, mileage, priceund so weiter, insgesamt 65.
  2. Jetzt kann ich teilen , dass und habe VehicleTabelle, VehicleInterior, VehicleExterior, VehicleTechnical, VehicleExtra(alle eins-zu-eins mit VehicleHaupttabelle).

Nehmen wir an, ich habe ungefähr 5 Millionen Reihen (Fahrzeuge).

Weiter SELECTmit einer WHEREKlausel: Wird die Leistung besser durchsucht (beide Fälle mindestens indiziert IDs):

  1. Vehicle Tabelle mit 65 Spalten oder
  2. VehicleTabelle mit JOINSvier weiteren Tabellen (alle mit 5 Millionen Zeilen), um alle Daten zurückzugeben, die sich auf Vehicle?

(Berücksichtigen Sie gemäß Datenbankmodul PostgreSQL und / oder MySQL).

Schätzen Sie wirklich detaillierte Erkenntnisse, die Sie aus Ihren bisherigen Erfahrungen haben könnten?


1
Ein Grund tun , um diese (vertikale Partitionierung) ist , wenn Sie Fragen haben , die sich mit den Spalten aus VehicleInterior, andere Abfragen , die sich mit Spalten von nur VehicleTechnicalusw. Oder wenn es viele Reihen / Fahrzeuge , die absolut keine Informationen haben über (zum Beispiel) , VehicleExtraso Anstelle vieler Zeilen mit vielen Nullen in einer Tabelle haben Sie Zeilen in den restlichen Tabellen und keine Zeilen inVehicleExtra
ypercubeᵀᴹ

Antworten:


14

Angenommen, es handelt sich um 1: 1-Beziehungen zwischen allen Tabellen.

Insgesamt Lagerung ist praktisch immer ( im Wesentlichen) billiger mit einer einzigen Tabelle anstelle von mehreren Tabellen in 1: 1 - Beziehung. Jede Zeile hat einen Overhead von 28 Bytes sowie normalerweise ein paar Bytes mehr für zusätzliches Auffüllen. Und Sie müssen die PK-Spalte mit jeder Tabelle speichern. Und haben Sie einen separaten (redundanten) Index für jede dieser Spalten ... Größe ist wichtig für die Leistung.

Dies gilt sogar, wenn viele Spalten in den meisten Zeilen NULL sind, da NULL-Speicher sehr billig ist :

Beim Abrufen aller Spalten ist eine einzelne Tabelle wesentlich schneller als 5 miteinander verbundene Tabellen. Es ist auch viel einfacher . Das Verknüpfen von fünf Tabellen kann schwierig sein, wenn nicht alle Zeilen in allen Tabellen vorhanden sind. Unter WHEREBedingungen, die auf eine einzelne Tabelle abzielen, ist es einfach genug, andere Tabellen anzuhängen LEFT JOIN. Nicht so trivial, wenn Sie Prädikate für mehrere Tabellen haben ...

Die vertikale Partitionierung kann die Leistung bestimmter Abfragen noch verbessern. Wenn beispielsweise 90% Ihrer Abfragen dieselben 5 von 65 verfügbaren Spalten abrufen, ist dies schneller, wenn eine Tabelle nur diese 5 Spalten enthält.

OTOH, Sie können möglicherweise solche Abfragen in einigen ausgewählten Spalten mit einem "abdeckenden" Index bearbeiten, der nur Index-Scans ermöglicht .

Ein weiterer Kandidat für die vertikale Partitionierung: Wenn Sie nur für wenige Spalten viele Aktualisierungen haben , während sich der Rest kaum ändert. In einem solchen Fall kann es erheblich billiger sein, Zeilen zu teilen, da Postgres für jedes Update eine neue Zeilenversion schreibt. Es gibt Ausnahmen für große Werte, die außerhalb der Zeile gespeichert werden ("TOASTed"). Mehr Details:

Es kommt wirklich auf die gesamte Situation an. Wenn Sie Zweifel haben, entscheiden Sie sich für die einfache Lösung, einen einzigen Tisch zu haben, insbesondere wenn er die Realität gut darstellt: In Ihrem Beispiel sind dies alles Attribute eines Autos und machen zusammen Sinn.


Aktualisierungen sind selten, wenn keine und die Auswahl meistens für alle Spalten (Fahrzeugdetailseite) und Hauptinformationen (wenige Spalten) für die Suchergebnisliste erfolgt. Die beste Lösung wären möglicherweise zwei Tabellen: eine mit Hauptinformationen (wenige Spalten) ) und die andere Tabelle mit den restlichen Spalten. Was halten Sie in diesem Fall von SQL-Joins mit beispielsweise 5 Millionen Zeilen - was die Leistung betrifft? Übrigens danke für Ihre detaillierten Bemühungen
Urim Kurtishi

1
@octavius: Eine einzelne Tabelle mit einem mehrspaltigen Index für die wenigen Spalten, um nur Index-Scans für die Ergebnisliste zu ermöglichen, ist möglicherweise die beste Route. ( Beachten Sie, dass die Spaltenfolge in btree-Indizes von Bedeutung ist .) Verknüpfungen sind nicht so teuer, aber ohne Verknüpfung immer noch schneller. Die zusätzliche Speichergröße und die Verteilung der Daten für mehrere Tabellen können die größere Verlangsamung sein (mehr Datenseiten, die für jede Abfrage gelesen werden müssen).
Erwin Brandstetter

1
Ich stimme Erwins Kommentar zu, dass die Antwort wirklich von der vollständigen Situation oder der tatsächlichen Nutzung abhängt. Wenn Sie festgestellt haben, dass sich 90% der Abfragen auf eine kleine Teilmenge der Daten beziehen und die Leistung von größter Bedeutung ist, kann es sinnvoll sein, den zusätzlichen Aufwand in viele Tabellen zu rechtfertigen. Persönlich würde ich versuchen, das Datenmodell einfach zu halten. Wie schnell ist schnell genug? Wie viel Aufwand betreiben Sie, um diese letzte Millisekunde zu sparen? Haben Sie versucht, Daten zu verspotten und Tests durchzuführen?
Sir schwört viel

@ErwinBrandstetter Sie haben in Ihrer Antwort erwähnt, dass die Beziehung 1: 1 ist. Was ist mit 1: N-Beziehungsschiffen?
Schlank

Für eine 1: N-Beziehung benötigen Sie ohnehin zwei separate Tabellen. Außer wenn Sie mehrere Zeilen in ein Array oder einen Dokumenttyp packen. Dann kommt es darauf an. Die hier beschriebenen Grundsätze gelten unabhängig davon. Ihre Zugriffsmuster und Indexstrategien können einen Unterschied machen. Stellen Sie eine neue Frage, wenn Sie genauer sein möchten.
Erwin Brandstetter

0

Eine Auswahl für eine einzelne Tabelle sollte immer schneller sein. Sobald Sie Ihr Fahrzeug gefunden haben, haben Sie bereits alle Details.

Sie verlieren jedoch die Effizienz der Normalisierung. Zum Beispiel, wenn 1 Auto viele Modelle mit unterschiedlichen Optionen hatte.

Ist das eine Referenz-Datenbank aller Autos? Oder eine Liste von Gebrauchtfahrzeugen? Gibt es viele Beispiele für dieselbe Marke / dasselbe Modell mit denselben Optionen?

Bearbeiten: Ich sollte meine Antwort als generische rdbms und nicht als postgres-spezifisch qualifizieren. Ich verweise auf @ Erwins detaillierte Antwort speziell für Postgres


2
"Eine Auswahl an einem einzelnen Tisch sollte immer schneller sein." Warum?
Ypercubeᵀᴹ

Fahrzeughersteller und Fahrzeugmodell sind unterschiedliche Tabellen, daher enthält der Fahrzeugtisch Fremdschlüssel für Fahrzeughersteller und Fahrzeugmodell. Ich denke nicht, dass Normalisierung hier ein Problem ist. Ich verstehe, dass die Auswahl für eine einzelne Tabelle schneller wäre, aber wir haben eine andere Situation, wie sich die Zeile mit vielen Spalten auf die Leistung usw. auswirkt, im Vergleich zu Tabellen mit weniger Spalten (aber nur wenige Tabellen - 5 davon mit
Verknüpfungen

Entschuldigung, ich hatte den Punkt verpasst, dass Marke und Modell bereits getrennt waren. Die Kurzversion ist, dass Joins Aufwand für das Datenbankmodul erfordern. Wenn Sie eine einzelne Tabelle / Zeile verwenden, erhalten Sie alles in einer einzigen Auswahl, was zu weniger E / A und Overhead für die DB-Engine führen würde.
Sir Swears-a-lot
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.