Verwenden Sie MySQL, um regelmäßig Multi-Way-Joins für Tabellen mit mehr als 100 GB durchzuführen?

11

Hintergrund :
Ich habe eine Webanwendung erstellt, die ich relativ gut skalieren möchte. Ich weiß, dass ich nicht Google oder Twitter bin, aber meine App verwendet eine ziemlich große Datenmenge für jeden Benutzer und hat daher ziemlich hohe Datenanforderungen. Ich möchte bereit sein, einigermaßen gut zu skalieren, ohne später alles neu entwerfen zu müssen.

Ich betrachte mich als Softwareentwickler, nicht als Datenbankexperte. Deshalb poste ich hier. Hoffentlich kann mir jemand mit viel mehr Datenbankkenntnissen Ratschläge geben.

Mit einer relativ großen Anzahl von Benutzern, aber nichts wie Facebook-Nummern, erwarte ich eine Datenbank, die so aussieht:

Ein "großer Tisch":

  • 250 Millionen Datensätze
  • 20 Spalten
  • Ungefähr 100 GB Daten
  • Hat einen indizierten Bigint (20) Fremdschlüssel
  • Hat eine indizierte varchar (500) string_id-Spalte
  • Hat eine int (11) "Wert" -Spalte

4 weitere Tabellen:

  • Jeweils 10 Millionen Datensätze
  • Jeweils ca. 2 - 4 GB Daten
  • Jede dieser Tabellen hat 4 - 8 Spalten
  • Eine Spalte ist datetime date_created
  • Eine Spalte ist die Spalte varchar (500) string_id
  • In einem Join werden eine oder zwei Spalten aus jeder dieser Tabellen ausgewählt

Eine dieser Tabellen wird zum Speichern von Durchschnittswerten verwendet. Das Schema lautet bigint (20) id, varchar (20) string_id, datetime date_created, float durchschnitt_value

Was ich tun möchte - zwei relativ teure Abfragen:

  1. Berechnen Sie neue Durchschnittswerte:

    • Wählen Sie mit einem Fremdschlüssel bis zu mehrere Millionen separate Datensätze aus der großen Tabelle aus.
    • Berechnen Sie einen neuen Durchschnitt, gruppieren Sie nach der string_id.
    • Fügen Sie die Ergebnisse in die Durchschnittstabelle ein.
    • Wie derzeit erstellt, verwendet diese Abfrage zwei Verknüpfungen.
  2. Erstellen Sie de-normalisierte, schreibgeschützte Datensätze für Benutzer:

    • Verwenden Sie einen Fremdschlüssel, um zwischen 1.000 und 40.000 Datensätze aus der großen Tabelle auszuwählen.
    • Verbinden Sie sich mit jeder der anderen vier Tabellen im neuesten Datensatz mit der Zeichenfolgen-ID-Spalte.
    • Fügen Sie die Ergebnisse in eine de-normalisierte Tabelle ein.
    • Diese Datensätze werden vom Front-End verwendet, um Benutzern Informationen anzuzeigen.
    • Wie derzeit erstellt, verwendet diese Abfrage vier Verknüpfungen.

Ich plane, jede dieser teuren Abfragen in einer Batch-Back-End-Datenbank auszuführen, die ihre Ergebnisse an einen Echtzeit-Front-End-DB-Server überträgt, der Anforderungen von Benutzern verarbeitet. Diese Abfragen werden in regelmäßigen Abständen ausgeführt. Ich habe nicht entschieden, wie oft. Die durchschnittliche Abfrage könnte möglicherweise einmal pro Tag durchgeführt werden. Die De-Normalisierungsabfrage muss häufiger ausgeführt werden - möglicherweise alle paar Minuten.

Jede dieser Abfragen wird derzeit in MySQL in wenigen Sekunden auf einem sehr einfachen Computer mit einem Datensatz mit 100.000 Datensätzen in der „großen Tabelle“ ausgeführt. Ich bin sowohl besorgt über meine Skalierbarkeit als auch über die Kosten der Skalierung.

Fragen :

  1. Scheint dieser Ansatz sinnvoll? Stimmt etwas aus einer Gesamtperspektive offensichtlich nicht?
  2. Ist ein RDBMS das richtige Tool, oder sollte ich mir andere "Big Data" -Lösungen wie die der Hadoop-Familie ansehen? Meine Neigung ist es, ein RDBMS zu verwenden, da die Daten strukturiert sind und gut in das relationale Modell passen. Ab einem bestimmten Punkt kann ich jedoch möglicherweise kein RDBMS mehr verwenden. Ist das wahr? Wann würde dieser Schalter benötigt?
  3. Wird es funktionieren? Können diese Abfragen in angemessener Zeit ausgeführt werden? Ich kann vielleicht Stunden auf Abfrage Nr. 1 warten, aber Abfrage Nr. 2 sollte in Minuten abgeschlossen sein.
  4. Was muss ich aus Hardware-Sicht beachten? Was sind meine RAM- und CPU-Engpässe wahrscheinlich? Ich gehe davon aus, dass es wichtig ist, Indizes im RAM zu halten. Gibt es noch etwas, das ich berücksichtigen sollte?
  5. Irgendwann muss ich wahrscheinlich meine Daten partitionieren und mehrere Server verwenden. Scheint mein Anwendungsfall bereits in dieser Kategorie zu sein, oder kann ich eine einzelne Maschine für eine Weile vertikal skalieren? Funktioniert das mit dem 10-fachen der Daten? 100x?
xnickmx
quelle
Dieser ist schwer gründlich zu beantworten. Vielleicht ist es besser, wenn Sie sich über die Leistungsmerkmale von MySQL-Abfragen im Allgemeinen informieren, damit Sie wissen, was Sie erwarten können.; Eine Sache, die Sie natürlich immer tun können, ist, 20 Festplatten in den Server einzulegen, damit Sie mit etwa 3 GB / s lesen können. Aber ich denke, Sie sind nach einer gründlichen Nur-Software-Antwort.
usr

Antworten:

4

Haben Sie versucht, mehr Daten zu stapeln und zu vergleichen? 100K Zeilen spielen keine Rolle. Probieren Sie 250M oder 500M aus, wie Sie es erwarten, und sehen Sie, wo die Engpässe liegen.

Ein RDBMS kann viele Dinge tun, wenn Sie die Einschränkungen genau beachten und versuchen, mit den Stärken des Systems zu arbeiten. Sie sind in einigen Dingen außergewöhnlich gut und in anderen schrecklich. Sie müssen also experimentieren, um sicherzugehen, dass sie richtig passen.

Bei einigen Stapelverarbeitungsjobs können Sie Flatfiles wirklich nicht schlagen, die Daten in den Arbeitsspeicher laden, sie mit einer Reihe von Schleifen und temporären Variablen zerschlagen und die Ergebnisse ausgeben. MySQL wird niemals in der Lage sein, diese Geschwindigkeit zu erreichen, aber wenn es richtig eingestellt und richtig verwendet wird, kann es in einer Größenordnung liegen.

Sie möchten lediglich untersuchen, wie Ihre Daten partitioniert werden können. Haben Sie einen großen Datensatz mit zu vielen Querverbindungen, um ihn aufteilen zu können, oder gibt es natürliche Orte, an denen Sie ihn partitionieren können? Wenn Sie es partitionieren können, haben Sie nicht eine Tabelle mit einem ganzen Stapel von Zeilen, sondern möglicherweise viele wesentlich kleinere. Kleinere Tabellen mit viel kleineren Indizes weisen tendenziell eine bessere Leistung auf.

Aus Hardware-Sicht müssen Sie testen, wie Ihre Plattform funktioniert. Manchmal ist das Gedächtnis wichtig. In anderen Fällen handelt es sich um Festplatten-E / A. Es hängt wirklich davon ab, was Sie mit den Daten machen. Sie müssen genau auf Ihre CPU-Auslastung achten und nach hohen E / A-Werten suchen, um zu wissen, wo das Problem liegt.

Teilen Sie Ihre Daten nach Möglichkeit auf mehrere Systeme auf. Sie können MySQL Cluster verwenden, wenn Sie sich mutig fühlen, oder einfach viele unabhängige Instanzen von MySQL starten, in denen jeweils ein beliebiger Teil des gesamten Datensatzes mithilfe eines sinnvollen Partitionierungsschemas gespeichert wird.

Tadman
quelle
@tadman Danke für deinen Rat. Mir ist klar, dass es keinen Ersatz dafür gibt, es tatsächlich auszuprobieren. Ich habe es nicht mit 250 Millionen Zeilen verglichen, weil ich zuerst sicherstellen wollte, dass an meinem Ansatz offensichtlich nichts falsch ist. Es hört sich so an, als gäbe es keine. Darüber hinaus ist es eine Herausforderung, so viele Daten zu erhalten und auf eine realistische Art und Weise zu erstellen, deren Lösung ich noch nicht herausgefunden habe. Ich habe einige Möglichkeiten, die Daten zu partitionieren. Ich denke, ich werde als nächstes versuchen, meine Daten
hochzufahren
1

Übersichtstabellen.

Berechnen Sie jeden Tag aggregierte Informationen für die Tagesdaten. Tragen Sie das in die "Zusammenfassung" -Tabelle (n) ein. Stellen Sie Ihre Fragen gegen sie. Leicht 10 mal so schnell.

Für weitere Informationen geben Sie bitte an

  • SHOW CREATE TABLE (wie es jetzt steht)
  • Tischgrößen (die Sie erwähnt haben)
  • Vorgeschlagene SELECTs

Einige offensichtliche Dinge ...

  • BIGINT ist selten garantiert. Es dauert 8 Bytes. INT UNSIGNED nimmt 4 und erlaubt Werte 0..4billion. Und es gibt MEDIUMINT usw.
  • Mehrere Indizes in der Faktentabelle sind normalerweise ein ernstes Leistungsproblem, insbesondere bei INSERTs. Haben Sie dort ein Problem?
  • DATETIME ist 8 Bytes; TIMESTAMP ist 4
  • Explizite AUSLÄNDISCHE SCHLÜSSELBESCHRÄNKUNGEN sind nett, aber teuer
  • JOINs können ein Leistungsproblem sein oder auch nicht. müssen die SELECT und CREATEs sehen.
  • 100 GB sind eine schöne Größe für eine 'große' MySQL-Datenbank. Ich vermute, es könnte ohne Hadoop usw. funktionieren. Ich beschäftige mich jetzt mit einer solchen Datenbank - die meisten UI-Seiten antworten in weniger als einer Sekunde, obwohl die Daten ziemlich kompliziert sind.
  • Werden Sie irgendwann Daten "löschen"? (Dies führt zum Hauptanwendungsfall für die PARTITIONIERUNG.)

"Kleiner -> zwischenspeicherbarer -> schneller

Rick James
quelle
0

Wenn Sie Ihre Front-End-Daten bereitstellen möchten, können Sie es nicht übertreffen, Trigger zum Einfügen in materialisierte Ansichten zu verwenden, die mit dem Back-End synchronisiert, aber für die Bereitstellung der Daten optimiert sind, es sei denn, es gibt ständig viele Einfügungen. Natürlich müssen Sie Joins usw. usw. in diesen Triggern auf ein Minimum beschränken. Eine Strategie, die ich verwendet habe, besteht darin, diese Einfügungen / Aktualisierungen in eine Zwischentabelle zu stellen und sie dann jede Minute oder so weiterzuleiten. Es ist viel einfacher, einen Datensatz zu senden als 4 GB Datensätze. Das Streamen von 4 GB Daten dauert lange, selbst wenn Sie die gesuchten Datensätze schnell finden.

Ich stimme Tadman zu. Am besten profilieren Sie es mit der Art von Daten, die Sie für die Art von System erwarten, die Sie möchten.

wes.stueve
quelle
Wie ich in meinem Beitrag erwähnt habe, hängen die Ansichten von einer Abfrage ab, bei der vier Verknüpfungen in Tabellen mit mehreren zehn Millionen Datensätzen verwendet werden. Daher sehe ich nicht wirklich, wie eine materialisierte Ansicht helfen wird.
Xnickmx
Trigger sind für diese Datenbankgröße möglicherweise nicht schnell genug. Wie viele INSERTs pro Sekunde finden statt?
Rick James
1
@xnickmx Wenn es nicht so viele Einfügungen / Aktualisierungen gibt, machen es Trigger einfach / performant, denormalisierte Daten synchron zu halten. Wenn Einfügungen / Aktualisierungen schneller ausgeführt werden müssen, stellen Sie sie wie folgt in die Warteschlange: blog.shlomoid.com/2008/04/… oder backen Sie Ihre eigenen. Auf diese Weise müssen Sie sich nicht mit den vorhandenen 100 Millionen Zeilentabellen verbinden, um die neuen Daten zu erhalten, da Sie beim Auslösen des Triggers die Tatsache ausnutzen, dass Sie die neuen Daten sofort kennen und sie einfach als Teil des TX denormalisieren können oder stellen Sie es später zur Denormalisierung in die Warteschlange.
wes.stueve
@ RickJames vereinbart. Sie müssen die Anzahl der Einfügungen für diese Art von Strategie berücksichtigen und wie schnell sie verarbeitet werden müssen.
wes.stueve