it-swarm.com.de

Umgang mit sehr großen Datenmengen mit MySQL

Entschuldigung für den langen Beitrag!

Ich habe eine Datenbank mit ca. 30 Tabellen (InnoDB-Engine). Nur zwei dieser Tabellen, nämlich "transaction" und "shift", sind ziemlich groß (die erste hat 1,5 Millionen Zeilen und shift 23.000 Zeilen). Jetzt funktioniert alles einwandfrei und ich habe kein Problem mit der aktuellen Datenbankgröße.

Wir werden jedoch eine ähnliche Datenbank haben (gleiche Datentypen, Design, ..), aber viel größer, zB wird die "Transaktions" -Tabelle ungefähr 1 Milliarde Datensätze haben (ca. 2,3 Millionen Transaktionen pro Tag) und wir überlegen, wie wir mit einem solchen Datenvolumen in MySQL umgehen sollen? (Es ist sowohl Lese- als auch Schreibintensiv). Ich habe viele verwandte Beiträge gelesen, um zu sehen, ob Mysql (und insbesondere die InnoDB-Engine) mit Milliarden von Datensätzen gute Ergebnisse erzielen kann, aber ich habe immer noch einige Fragen. Einige dieser verwandten Beiträge, die ich gelesen habe, sind im Folgenden aufgeführt:

Was ich bisher verstanden habe, um die Leistung bei sehr großen Tabellen zu verbessern:

  1. (für innoDB-Tabellen, was mein Fall ist) Erhöhen des innodb_buffer_pool_size (z. B. bis zu 80% des RAM). Außerdem habe ich einige andere Einstellungen für die MySQL-Leistung gefunden hier im percona-Blog
  2. richtige Indizes für die Tabelle haben (mit EXPLAN für Abfragen)
  3. partitionierung der Tabelle
  4. MySQL-Sharding oder Clustering

Hier sind meine Fragen/Verwirrungen:

  • In Bezug auf die Partitionierung habe ich einige Zweifel, ob wir sie verwenden sollen oder nicht. Einerseits haben viele Leute vorgeschlagen, die Leistung zu verbessern, wenn der Tisch sehr groß ist. Andererseits habe ich viele Beiträge gelesen, in denen es heißt, dass die Abfrageleistung nicht verbessert wird und Abfragen nicht schneller ausgeführt werden (z. B. hier und hier ). Außerdem habe ich in MySQL Reference Manual gelesen, dass InnoDB-Fremdschlüssel und MySQL-Partitionierung nicht kompatibel sind (wir haben Fremdschlüssel).

  • Was die Indizes betrifft, so funktionieren sie derzeit gut, aber soweit ich weiß, ist die Indizierung für sehr große Tabellen restriktiver (wie Kevin Bedell in seiner Antwort hier erwähnt hat). Außerdem beschleunigen Indizes das Lesen, während das Schreiben verlangsamt wird (Einfügen/Aktualisieren). Sollten wir für das neue, ähnliche Projekt, das diese große Datenbank haben wird, zuerst alle Daten einfügen/laden und dann Indizes erstellen? (um den Einsatz zu beschleunigen)

  • Wenn wir die Partitionierung für unsere große Tabelle ("Transaktions" -Tabelle) nicht verwenden können, was ist eine alternative Option, um die Leistung zu verbessern? (mit Ausnahme von MySQl-Variableneinstellungen wie innodb_buffer_pool_size). Sollten wir MySQL-Cluster verwenden? (Wir haben auch viele Joins)

BEARBEITEN

Dies ist das show create table Anweisung für unsere größte Tabelle mit dem Namen "transaction":

  CREATE TABLE `transaction` (
 `id` int(11) NOT NULL AUTO_INCREMENT,
 `terminal_transaction_id` int(11) NOT NULL,
 `fuel_terminal_id` int(11) NOT NULL,
 `fuel_terminal_serial` int(11) NOT NULL,
 `xboard_id` int(11) NOT NULL,
 `gas_station_id` int(11) NOT NULL,
 `operator_id` text NOT NULL,
 `shift_id` int(11) NOT NULL,
 `xboard_total_counter` int(11) NOT NULL,
 `fuel_type` int(11) NOT NULL,
 `start_fuel_time` int(11) NOT NULL,
 `end_fuel_time` int(11) DEFAULT NULL,
 `preset_amount` int(11) NOT NULL,
 `actual_amount` int(11) DEFAULT NULL,
 `fuel_cost` int(11) DEFAULT NULL,
 `payment_cost` int(11) DEFAULT NULL,
 `purchase_type` int(11) NOT NULL,
 `payment_ref_id` text,
 `unit_fuel_price` int(11) NOT NULL,
 `fuel_status_id` int(11) DEFAULT NULL,
 `fuel_mode_id` int(11) NOT NULL,
 `payment_result` int(11) NOT NULL,
 `card_pan` text,
 `state` int(11) DEFAULT NULL,
 `totalizer` int(11) NOT NULL DEFAULT '0',
 `shift_start_time` int(11) DEFAULT NULL,
 PRIMARY KEY (`id`),
 UNIQUE KEY `terminal_transaction_id` (`terminal_transaction_id`,`fuel_terminal_id`,`start_fuel_time`) USING BTREE,
 KEY `start_fuel_time_idx` (`start_fuel_time`),
 KEY `fuel_terminal_idx` (`fuel_terminal_id`),
 KEY `xboard_idx` (`xboard_id`),
 KEY `gas_station_id` (`gas_station_id`) USING BTREE,
 KEY `purchase_type` (`purchase_type`) USING BTREE,
 KEY `shift_start_time` (`shift_start_time`) USING BTREE,
 KEY `fuel_type` (`fuel_type`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=1665335 DEFAULT CHARSET=utf8 ROW_FORMAT=COMPACT

Vielen Dank für Ihre Zeit,

28
mOna
  • Kann MySQL Abfragen in Milliarden von Zeilen sinnvoll ausführen? - MySQL kann Milliarden von Zeilen verarbeiten. "Vernünftigerweise" hängt von den Abfragen ab; Lass sie uns sehen.

  • Ist InnoDB (MySQL 5.5.8) die richtige Wahl für mehrere Milliarden Zeilen? - 5.7 hat einige Verbesserungen, aber 5.5 ist trotz des Seins ziemlich gut fast 6 8 Jahre alt und kurz davor, nicht mehr unterstützt zu werden.

  • Bester Datenspeicher für Milliarden von Zeilen - Wenn Sie "Engine" meinen, dann InnoDB.

  • Wie groß kann eine MySQL-Datenbank werden, bevor sich die Leistung verschlechtert? Dies hängt wiederum von den Abfragen ab. Ich kann Ihnen eine 1K-Zeilentabelle zeigen, die zusammenbricht. Ich habe mit milliardenreihigen Tischen gearbeitet, die sich summten.

  • Warum kann MySQL bei großen Tabellen langsam sein? - Bereichsüberprüfungen führen zu E/A, was der langsame Teil ist.

  • Kann Mysql Tabellen verarbeiten, die ungefähr 300 Millionen Datensätze enthalten? - wieder ja. Die Grenze liegt irgendwo bei einer Billion Reihen.

  • (für innoDB-Tabellen, was mein Fall ist) Erhöhen der innodb_buffer_pool_size (z. B. bis zu 80% des RAM). Außerdem habe ich hier im percona-Blog einige andere Einstellungen zur Optimierung der MySQL-Leistung gefunden - ja

  • richtige Indizes für die Tabelle (mit EXPLAN für Abfragen) - sehen wir sie uns an. In diesem kritischen Bereich können viele Fehler gemacht werden.

  • partitionierung der Tabelle - "Partitionierung ist kein Allheilmittel!" Ich harfe darauf in meinem Blog

  • MySQL Sharding - Derzeit ist dies DIY

  • MySQL-Clustering - Die derzeit beste Antwort ist eine Galera-basierte Option (PXC, MariaDB 10, DIY mit Oracle). Die "Gruppenreplikation" von Oracle ist ein tragfähiger Konkurrent.

  • Die Partitionierung unterstützt weder FOREIGN KEY Noch "global" UNIQUE.

  • UUIDs verlangsamen auf der Skala, von der Sie sprechen, das System nicht nur, sondern töten es sogar. UUIDs des Typs 1 können eine Problemumgehung sein.

  • Einfüge- und Indexerstellungsgeschwindigkeit - Es gibt zu viele Variationen, um eine einzige Antwort zu geben. Lassen Sie uns Ihren vorläufigen CREATE TABLE Und Ihre Absicht, die Daten einzugeben, sehen.

  • Viele Verknüpfungen - "Normalisieren, aber nicht zu stark normalisieren." Normalisieren Sie insbesondere keine Datenzeiten oder Gleitkommazahlen oder andere "kontinuierliche" Werte.

  • Erstellen Sie Übersichtstabellen

  • 2,3 Millionen Transaktionen pro Tag - Wenn das 2,3 Millionen Einfügungen (30/Sek.) Sind, gibt es kaum ein Leistungsproblem. Wenn dies komplexer ist, sind möglicherweise RAID, SSD, Batching usw. erforderlich.

  • umgang mit einem solchen Datenvolumen - Wenn die meisten Aktivitäten in den "letzten" Zeilen stattfinden, wird die Aktivität im buffer_pool schön zwischengespeichert, wodurch E/A vermieden werden. Wenn die Aktivität "zufällig" ist, hat MySQL (oder jeder andere ) E/A-Probleme.

  • Das Verkleinern der Datentypen hilft in einer Tabelle wie der Ihren. Ich bezweifle, dass Sie 4 Bytes benötigen, um fuel_type Anzugeben. Es gibt mehrere 1-Byte-Ansätze.

41
Rick James

Wenn Sie Milliarden von Zeilen sammeln, ist es besser (wenn möglich), die Daten zu konsolidieren, zu verarbeiten, zusammenzufassen bevor zu speichern. Behalten Sie die Rohdaten in einer Datei, wenn Sie glauben, dass Sie wieder darauf zugreifen müssen.

Dadurch werden die meisten Ihrer Fragen und Bedenken beseitigt und die Verarbeitung beschleunigt.

2
Rick James