MySQL-Lernaufzeichnung: Blutiger Vorfall durch KEY-Partition verursacht

MySQL-Lernaufzeichnung: Blutiger Vorfall durch KEY-Partition verursacht

Nachfragehintergrund

Ein Teil der Daten in der Geschäftstabelle tb_image ist wie folgt, wobei die ID eindeutig ist, die image_no jedoch nicht. image_no stellt die Nummer jeder Datei dar. Jede Datei generiert mehrere Dateien im Geschäftssystem. Die eindeutige ID jeder Datei ist das Feld id:

Einige Informationen zur Geschäftstabelle tb_image lauten wie folgt:

  • Abfrage nach Bildnummer und Abfrage nach ID;
  • Bestandsdaten 2kw;
  • Das tägliche Wachstum beträgt etwa 4 Wochen;
  • Das tägliche Abfragevolumen beträgt etwa 200.000;
  • Da es sich um ein System ohne ToC handelt, ist die Obergrenze für die Parallelität sichtbar.

Lösungsauswahl

Aufgrund der obigen Geschäftsanalyse ist eine Trennung von Datenbank und Tabellen völlig unnötig. Wenn eine einzelne Datenbank geteilt wird, besteht eine Lösung darin, redundantes Sharding zu verwenden (d. h. eine Kopie der Daten wird mit „image_no“ als Sharding-Schlüssel gespeichert und die andere Kopie der Daten wird mit „id“ als Sharding-Schlüssel gespeichert), da Abfragen auf „image_no“ und „id“ basieren müssen. Eine andere Lösung besteht darin, nur „image_no“ als Sharding-Schlüssel zu verwenden und die Geschäftsebene die Ergebnisse basierend auf den Abfrageanforderungen der ID zusammenzuführen oder Middleware von Drittanbietern einzuführen.

Da es komplizierter ist, eine einzelne Datenbank in Tabellen aufzuteilen, haben wir uns für die Partitionierungsfunktion entschieden. Darüber hinaus kann die Kapazitätsbewertungslösung mit Partitionstabellen und 128 Partitionen (jede Partition hat ein Datenvolumen auf kw-Ebene) vollständig sicherstellen, dass das Geschäft mindestens 15 Jahre lang stabil läuft (der orangefarbene Teil in der Abbildung entspricht eher dem tatsächlichen Wachstum unseres Geschäfts):

Da RANGE-, LIST- und HASH-Partitionen keine VARCHAR-Spalten unterstützen, wird außerdem entschieden, KEY-Partitionen zu verwenden. Die offizielle Einführung ihres Prinzips besteht darin, den in MySQL integrierten Hash-Algorithmus zu verwenden und dann den Modul der Partitionsnummer zu nehmen.

Leistungstests

Nachdem Sie den Shard-Schlüssel als image_no ausgewählt und 128 Partitionen festgelegt haben, ist es an der Zeit, Daten für Machbarkeits- und Leistungstests zu laden. Der Grund, warum die Anzahl der Partitionen auf 128 festgelegt wurde, ist: 1,1 Milliarden/1 kW = 110 ≈ 128. Außerdem verwenden Programmierer gerne die Zweierpotenz, wie Sie wissen. Der Albtraum beginnt jedoch mit der Partitionsnummer 128.

Ich habe versucht, 100.000 Daten in 128 Partitionen einzufügen. Nach dem Einfügen trat ein überraschendes Phänomen auf: In allen ungeraden Partitionen (p1, p3, p5, …, p2n-1) waren keine Daten vorhanden. Gleichzeitig enthielt jede gerade nummerierte Partition viele Daten, und sie war nicht sehr gleichmäßig. Wie in der folgenden Abbildung dargestellt:

Hinweis: Die IBD-Dateigröße von Partitionen mit ungeraden Nummern beträgt 112 KB. Dies ist die Initialisierungsgröße beim Erstellen der Partitionstabelle. Tatsächlich sind keine Daten vorhanden. Wir können dies mit SQL überprüfen: select partition_name, partition_expression, table_rows from information_schema.partitions where table_schema = schema() and table_name='image_subpart' ;, und einige der Ergebnisse werden in der folgenden Abbildung angezeigt:

Reichen 100.000 Daten nicht aus, um das Problem zu veranschaulichen? Im Durchschnitt enthält jede Partition fast 800 Datenelemente! Ok, machen wir etwas drastisches: Ich werde weitere 990-W-Daten einfügen, also insgesamt 1 kW Daten. Das Ergebnis ist immer noch dasselbe: Partitionen mit ungeraden Nummern haben keine Daten und Partitionen mit geraden Nummern haben Partitionen.

Fragen zum Nachdenken

Erinnern wir uns an das Prinzip der KEY-Partitionierung: Berechnen Sie den Hash-Wert des Shard-Schlüssels mit dem in MySQL integrierten Hash-Algorithmus und nehmen Sie dann den Modul der Partitionsnummer. Dieses Prinzip ist auch auf der offiziellen MySQL-Website zu finden. Klicken Sie bitte auf den Link: 22.2.5 KEY-Partitionierung: https://dev.mysql.com/doc/refman/5.7/en/partitioning-key.html. Der Originaltext lautet wie folgt:

Die Partitionierung nach Schlüssel ist der Partitionierung nach Hash ähnlich, mit dem Unterschied, dass bei der Hash-Partitionierung ein benutzerdefinierter Ausdruck verwendet wird und die Hash-Funktion für die Schlüsselpartitionierung vom MySQL-Server bereitgestellt wird. NDB Cluster verwendet zu diesem Zweck MD5(); für Tabellen, die andere Speicher-Engines verwenden, verwendet der Server seine eigene interne Hash-Funktion, die auf demselben Algorithmus wie PASSWORD() basiert.

**So einen beschissenen Hash-Algorithmus kann es auf der Welt doch nicht geben, oder? **Egal welchen Algorithmus Sie schreiben, es wird nicht so ungleichmäßig sein, oder? Derzeit frage ich mich, ob es eine Konfiguration ist, die die Ursache dafür ist. In den Anzeigevariablen sind jedoch keine partitionsbezogenen Variablen enthalten.

Zu dieser Zeit galoppierten zehntausend Pferde vorbei. Könnte es sein, dass Dokument und Quellcode nicht synchron sind? Schauen wir uns doch einmal den MySQL-Quellcode an. Schließlich kommt der Quellcode der Wahrheit am nächsten. Der Quellcode für die KEY-Partition befindet sich in der Datei sql_partition.cc. Der Autor hat einige Schlüsselquellcodes abgefangen, wie unten gezeigt. Auf den ersten Blick ist nichts falsch. Berechnen Sie zuerst den Hashwert des Partitionsfelds und nehmen Sie dann den Modul der Partitionsnummer:

/**
 Berechnen Sie die part_id für (SUB)PARTITION BY KEY
 @param Dateihandler zur Speicher-Engine
 @param field_array Array von Feldern für PARTTION KEY
 @param num_parts Anzahl der KEY-Partitionen
 @param func_value[out] Gibt den berechneten Hashwert zurück
 @return Berechnete Partitions-ID
*/
im Einklang
statische uint32 get_part_id_key(handler *datei,
               Feld **field_array,
               uint Anzahl_Teile,
               lang lang *Funktionswert)
{
 DBUG_ENTER("Teile-ID-Schlüssel abrufen");
 // Berechnen Sie den Hash-Wert des Partitionsfelds *func_value = file->calculate_key_hash_value(field_array);
 // Modulo die Anzahl der Partitionen DBUG_RETURN((uint32) (*func_value % num_parts));
}

Wenn Sie verzweifelt sind, suchen Sie bitte in der Suchmaschine nach „uneven KEY partition data“. Im CSDN-Forum (https://bbs.csdn.net/topics/390857704) gibt es in den Suchergebnissen einen Volksmeister, Hua Xia Xiao Zu, der wie folgt antwortete:

Ein Kollege hat die Kennwortfunktion analysiert und gemessen und festgestellt, dass bei der Schlüsselpartitionierung die Anzahl der Partitionen nur als Primzahl angegeben werden kann, um sicherzustellen, dass jede Partition Daten enthält. Ich habe es getestet, von 11 Partitionen bis 17 Partitionen. Nur die Daten in den Partitionen 11, 13 und 17 sind grundsätzlich gleichmäßig verteilt.

Zu dieser Zeit galoppierten weitere zehntausend Pferde vorbei. Aber während ich mich fragte, WAS ZUM F**K, war ich auch ein wenig aufgeregt, weil ich vielleicht eine Lösung gefunden hatte (obwohl ich immer noch nicht weiß, warum sich der eingebaute Hash-Algorithmus von MySQL so verhält). Schließlich testete ich die KEY-Partition erneut und kam zu folgendem Schluss:

  1. Wenn Sie die Partitionsnummer auf eine gerade Zahl wie 40, 64 oder 128 (PARTITIONS 64) festlegen, können die Partitionen mit ungeraden Nummern (p1, p3, p5, p7, … p2n-1) überhaupt keine Daten einfügen.
  2. Wenn Sie die Anzahl der Partitionen auf eine ungerade, aber keine Primzahl wie 63 oder 121 (PARTITIONEN 63) festlegen, enthalten alle Partitionen Daten, jedoch ungleichmäßig.
  3. Wenn Sie die Anzahl der Partitionen auf eine Primzahl wie 137 oder 31 (PARTITIONEN 137) festlegen, enthalten alle Partitionen Daten und sind sehr gleichmäßig verteilt.

Wie in der folgenden Abbildung dargestellt, ist dies die Situation, nachdem der Autor die Anzahl der Partitionen auf 127 angepasst und 1 Million Daten eingefügt hat. SQL beweist, dass die Datenmenge in jeder Partition nahezu gleich ist:

Zusammenfassung

Ich war schockiert, als ich erfuhr, dass es keine offizielle Erklärung für die enormen Fallstricke bei der Verwendung der KEY-Partition von MySQL gibt. Darüber hinaus gibt es einen MySQL-Fehler: Fehler Nr. 72428 Partitionierung durch KEY() führt zu ungleichmäßiger Datenverteilung

Studierende, die diesen Artikel lesen und großes Interesse haben, können versuchen, tiefer in dieses Thema einzutauchen. Der Autor wird sich auch die Zeit nehmen, tiefer in den MySQL-Quellcode einzutauchen, um herauszufinden, warum die Implementierung des Hash-Algorithmus so empfindlich auf die Anzahl der Partitionen reagiert.

Dies ist das Ende dieses Artikels über den blutigen Fall, der durch die KEY-Partitionierung von MySQL-Lerndatensätzen verursacht wurde. Weitere relevante Inhalte zum blutigen Fall der MySQL-KEY-Partitionierung finden Sie in den vorherigen Artikeln von 123WORDPRESS.COM oder in den folgenden verwandten Artikeln. Ich hoffe, dass jeder 123WORDPRESS.COM in Zukunft unterstützen wird!

Das könnte Sie auch interessieren:
  • Erste Schritte mit MySQL Sharding
  • Python implementiert das automatische Hinzufügen und Löschen von MySQL-Partitionen
  • Ausführliche Erläuterung der Kenntnisse zu MySql-Tabellen, Datenbanken, Sharding und Partitionierung
  • Detaillierte Erklärung des Unterschieds zwischen temporärer MySQL-Tabelle und Partitionstabelle
  • Detaillierte Erklärung der MySQL-Partitionstabelle
  • MySQL Best Practices: Grundlegende Arten von Partitionstabellen
  • Best Practices-Handbuch für partitionierte MySQL-Tabellen
  • Einführung in die Wissenspunkte MySql-Tabelle, Datenbank, Sharding und Partitionierung
  • Spezifische Implementierungsmethoden für MySQL-Tabellen-Sharding und -Partitionierung
  • Richtiger Einsatz von MySQL-Partitionstabellen
  • Erweiterte MySQL-Funktionen - detaillierte Erläuterung des Konzepts und des Mechanismus der Datentabellenpartitionierung

<<:  Erläuterung zu JavaScript-Anti-Shake und -Throttling

>>:  Docker Compose-Installationsmethoden in verschiedenen Umgebungen

Artikel empfehlen

JavaScript implementiert einfaches Scrollfenster

In diesem Artikelbeispiel wird der spezifische Ja...

Detaillierte Erklärung der Angular-Komponentenprojektion

Inhaltsverzeichnis Überblick 1. Einfaches Beispie...

Verständnis für Webdesign-Layout

<br />Hier ergibt sich ein Widerspruch: In k...

Verwendung der hasOwnProperty-Methode des js-Attributobjekts

Die Methode hasOwnProperty() des Objekts gibt ein...

Detaillierte Erklärung zum Anzeigen der MySQL-Speichernutzung

Vorwort Dieser Artikel stellt hauptsächlich die r...

Verwenden von Nginx zum Implementieren der Graustufenversion

Unter Graustufenfreigabe versteht man eine Freiga...

Wertschätzung des dezenten und eleganten Webdesigns in Schwarz, Weiß und Grau

Unter den klassischen Farbkombinationen kann wohl...