MariaDB
 sql >> Datenbank >  >> RDS >> MariaDB

Umgang mit großen Datenmengen mit MySQL und MariaDB

Die meisten Datenbanken werden mit der Zeit immer größer. Das Wachstum ist nicht immer schnell genug, um die Leistung der Datenbank zu beeinträchtigen, aber es gibt definitiv Fälle, in denen das passiert. Wenn dies der Fall ist, fragen wir uns oft, was getan werden könnte, um diese Auswirkungen zu verringern, und wie wir einen reibungslosen Datenbankbetrieb sicherstellen können, wenn wir mit Daten in großem Umfang umgehen.

Lassen Sie uns zunächst versuchen zu definieren, was ein „großes Datenvolumen“ bedeutet. Für MySQL oder MariaDB ist es unkomprimiertes InnoDB. InnoDB arbeitet so, dass es stark vom verfügbaren Arbeitsspeicher profitiert – hauptsächlich vom InnoDB-Pufferpool. Solange die Daten dort hineinpassen, wird der Festplattenzugriff auf die Verarbeitung von Schreibvorgängen minimiert – Lesevorgänge werden aus dem Speicher bedient. Was passiert, wenn die Daten den Speicherplatz sprengen? Immer mehr Daten müssen von der Festplatte gelesen werden, wenn auf Zeilen zugegriffen werden muss, die derzeit nicht zwischengespeichert sind. Wenn die Datenmenge zunimmt, wechselt die Arbeitslast von CPU-gebunden zu I/O-gebunden. Dies bedeutet, dass der Engpass nicht mehr die CPU ist (was der Fall war, als die Daten in den Speicher passten – der Datenzugriff im Speicher ist schnell, die Datentransformation und -aggregation ist langsamer), sondern das I/O-Subsystem (CPU-Operationen auf Daten sind Weg schneller als der Zugriff auf Daten von der Festplatte.) Mit der zunehmenden Einführung von Flash sind I/O-gebundene Workloads nicht mehr so ​​​​schrecklich wie früher in Zeiten von sich drehenden Laufwerken (wahlfreier Zugriff ist mit SSD viel schneller), aber der Leistungseinbruch ist immer noch da .

Eine andere Sache, die wir beachten müssen, ist, dass wir uns normalerweise nur um den aktiven Datensatz kümmern. Sicher, Sie können Terabyte an Daten in Ihrem Schema haben, aber wenn Sie nur auf die letzten 5 GB zugreifen müssen, ist dies eigentlich eine ziemlich gute Situation. Sicher, es stellt immer noch betriebliche Herausforderungen dar, aber in Bezug auf die Leistung sollte es immer noch in Ordnung sein.

Nehmen wir für die Zwecke dieses Blogs einfach an, und dies ist keine wissenschaftliche Definition, dass wir mit dem großen Datenvolumen den Fall meinen, in dem die aktive Datengröße die Größe des Speichers deutlich übersteigt. Es kann 100 GB sein, wenn Sie 2 GB Speicher haben, es kann 20 TB sein, wenn Sie 200 GB Speicher haben. Der entscheidende Punkt ist, dass Ihre Workload streng I/O-gebunden ist. Haben Sie etwas Geduld, während wir einige der Optionen besprechen, die für MySQL und MariaDB verfügbar sind.

Partitionierung

Der historische (aber vollkommen gültige) Ansatz zum Umgang mit großen Datenmengen besteht darin, Partitionierung zu implementieren. Die Idee dahinter ist, die Tabelle in Partitionen aufzuteilen, eine Art Untertabellen. Die Aufteilung erfolgt nach den vom Benutzer definierten Regeln. Sehen wir uns einige der Beispiele an (die SQL-Beispiele stammen aus der MySQL 8.0-Dokumentation)

MySQL 8.0 enthält die folgenden Arten der Partitionierung:

  • REIHE
  • LISTE
  • SPALTEN
  • HASH
  • SCHLÜSSEL

Es kann auch Unterpartitionen erstellen. Wir werden die Dokumentation hier nicht neu schreiben, aber wir möchten Ihnen dennoch einen Einblick in die Funktionsweise von Partitionen geben. Um Partitionen zu erstellen, müssen Sie den Partitionierungsschlüssel definieren. Es kann eine Spalte oder im Fall von RANGE oder LIST mehrere Spalten sein, die verwendet werden, um zu definieren, wie die Daten in Partitionen aufgeteilt werden sollen.

Die HASH-Partitionierung erfordert, dass der Benutzer eine Spalte definiert, die gehasht wird. Dann werden die Daten basierend auf diesem Hash-Wert in eine benutzerdefinierte Anzahl von Partitionen aufgeteilt:

CREATE TABLE employees (
    id INT NOT NULL,
    fname VARCHAR(30),
    lname VARCHAR(30),
    hired DATE NOT NULL DEFAULT '1970-01-01',
    separated DATE NOT NULL DEFAULT '9999-12-31',
    job_code INT,
    store_id INT
)
PARTITION BY HASH( YEAR(hired) )
PARTITIONS 4;

In diesem Fall wird Hash basierend auf dem Ergebnis erstellt, das von der Funktion YEAR() in der Spalte „hired“ generiert wird.

Die KEY-Partitionierung ist ähnlich, mit der Ausnahme, dass der Benutzer definiert, welche Spalte gehasht werden soll, und der Rest liegt in der Hand von MySQL.

Während HASH und KEY zufällig verteilte Daten über die Anzahl der Partitionen partitionieren, lassen RANGE und LIST den Benutzer entscheiden, was zu tun ist. RANGE wird üblicherweise mit Zeit oder Datum verwendet:

CREATE TABLE quarterly_report_status (
    report_id INT NOT NULL,
    report_status VARCHAR(20) NOT NULL,
    report_updated TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
)
PARTITION BY RANGE ( UNIX_TIMESTAMP(report_updated) ) (
    PARTITION p0 VALUES LESS THAN ( UNIX_TIMESTAMP('2008-01-01 00:00:00') ),
    PARTITION p1 VALUES LESS THAN ( UNIX_TIMESTAMP('2008-04-01 00:00:00') ),
    PARTITION p2 VALUES LESS THAN ( UNIX_TIMESTAMP('2008-07-01 00:00:00') ),
    PARTITION p3 VALUES LESS THAN ( UNIX_TIMESTAMP('2008-10-01 00:00:00') ),
    PARTITION p4 VALUES LESS THAN ( UNIX_TIMESTAMP('2009-01-01 00:00:00') ),
    PARTITION p5 VALUES LESS THAN ( UNIX_TIMESTAMP('2009-04-01 00:00:00') ),
    PARTITION p6 VALUES LESS THAN ( UNIX_TIMESTAMP('2009-07-01 00:00:00') ),
    PARTITION p7 VALUES LESS THAN ( UNIX_TIMESTAMP('2009-10-01 00:00:00') ),
    PARTITION p8 VALUES LESS THAN ( UNIX_TIMESTAMP('2010-01-01 00:00:00') ),
    PARTITION p9 VALUES LESS THAN (MAXVALUE)
);

Es kann auch mit anderen Spaltentypen verwendet werden:

CREATE TABLE employees (
    id INT NOT NULL,
    fname VARCHAR(30),
    lname VARCHAR(30),
    hired DATE NOT NULL DEFAULT '1970-01-01',
    separated DATE NOT NULL DEFAULT '9999-12-31',
    job_code INT NOT NULL,
    store_id INT NOT NULL
)
PARTITION BY RANGE (store_id) (
    PARTITION p0 VALUES LESS THAN (6),
    PARTITION p1 VALUES LESS THAN (11),
    PARTITION p2 VALUES LESS THAN (16),
    PARTITION p3 VALUES LESS THAN MAXVALUE
);

Die LIST-Partitionen arbeiten auf der Grundlage einer Werteliste, die die Zeilen über mehrere Partitionen hinweg sortiert:

CREATE TABLE employees (
    id INT NOT NULL,
    fname VARCHAR(30),
    lname VARCHAR(30),
    hired DATE NOT NULL DEFAULT '1970-01-01',
    separated DATE NOT NULL DEFAULT '9999-12-31',
    job_code INT,
    store_id INT
)
PARTITION BY LIST(store_id) (
    PARTITION pNorth VALUES IN (3,5,6,9,17),
    PARTITION pEast VALUES IN (1,2,10,11,19,20),
    PARTITION pWest VALUES IN (4,12,13,14,18),
    PARTITION pCentral VALUES IN (7,8,15,16)
);

Was ist der Sinn der Verwendung von Partitionen, die Sie vielleicht fragen? Der Hauptpunkt ist, dass die Lookups erheblich schneller sind als bei nicht partitionierten Tabellen. Angenommen, Sie möchten nach den Zeilen suchen, die in einem bestimmten Monat erstellt wurden. Wenn Sie Daten von mehreren Jahren in der Tabelle gespeichert haben, wird dies eine Herausforderung sein - ein Index muss verwendet werden, und wie wir wissen, helfen Indizes beim Auffinden von Zeilen, aber der Zugriff auf diese Zeilen führt zu einer Reihe von zufälligen Lesevorgängen der ganze Tisch. Wenn Sie Partitionen haben, die auf Jahr-Monat-Basis erstellt wurden, kann MySQL einfach alle Zeilen aus dieser bestimmten Partition lesen – es ist kein Zugriff auf den Index erforderlich, keine Notwendigkeit, zufällige Lesevorgänge durchzuführen:Lesen Sie einfach alle Daten aus der Partition nacheinander, und wir tun es alles klar.

Partitionen sind auch beim Umgang mit Datenrotation sehr nützlich. Wenn MySQL zu löschende Zeilen leicht identifizieren und sie einer einzelnen Partition zuordnen kann, können Sie die Partition kürzen, anstatt DELETE FROM table WHERE … auszuführen, das den Index zum Suchen von Zeilen verwendet. Dies ist bei der RANGE-Partitionierung äußerst nützlich - wenn wir beim obigen Beispiel bleiben, wenn wir Daten nur für 2 Jahre aufbewahren möchten, können wir einfach einen Cron-Job erstellen, der die alte Partition entfernt und eine neue, leere für den nächsten Monat erstellt.

InnoDB-Komprimierung

Wenn wir eine große Datenmenge haben (wobei wir nicht unbedingt an Datenbanken denken), kommt uns als Erstes in den Sinn, sie zu komprimieren. Es gibt zahlreiche Tools, die eine Option bieten, um Ihre Dateien zu komprimieren und ihre Größe erheblich zu reduzieren. InnoDB hat auch dafür eine Option - sowohl MySQL als auch MariaDB unterstützen die InnoDB-Komprimierung. Der Hauptvorteil der Komprimierung ist die Verringerung der E/A-Aktivität. Komprimierte Daten sind kleiner und können daher schneller gelesen und geschrieben werden. Eine typische InnoDB-Seite hat eine Größe von 16 KB, für SSD sind dies 4 E/A-Vorgänge zum Lesen oder Schreiben (SSD verwendet normalerweise 4-KB-Seiten). Wenn wir es schaffen, 16 KB auf 4 KB zu komprimieren, haben wir die E/A-Operationen nur um vier reduziert. Es hilft nicht wirklich viel in Bezug auf das Verhältnis von Datensatz zu Speicher. Tatsächlich kann es sogar noch schlimmer werden - MySQL muss die Seite dekomprimieren, um mit den Daten arbeiten zu können. Es liest jedoch eine komprimierte Seite von der Festplatte. Dies führt dazu, dass der InnoDB-Pufferpool 4 KB komprimierte Daten und 16 KB unkomprimierte Daten speichert. Natürlich gibt es Algorithmen, um unnötige Daten zu entfernen (unkomprimierte Seiten werden nach Möglichkeit entfernt und nur komprimierte bleiben im Speicher), aber Sie können in diesem Bereich keine allzu große Verbesserung erwarten.

Es ist auch wichtig zu beachten, wie die Komprimierung in Bezug auf die Speicherung funktioniert. Solid-State-Laufwerke sind heutzutage die Norm für Datenbankserver und sie haben einige spezifische Eigenschaften. Sie sind schnell, es ist ihnen egal, ob der Datenverkehr sequentiell oder zufällig ist (obwohl sie immer noch den sequentiellen Zugriff dem zufälligen vorziehen). Sie sind teuer für große Mengen. Sie leiden unter „abgenutzt“, da sie eine begrenzte Anzahl von Schreibzyklen bewältigen können. Die Komprimierung hilft hier erheblich - indem wir die Größe der Daten auf der Festplatte reduzieren, reduzieren wir die Kosten der Speicherschicht für die Datenbank. Indem wir die Größe der Daten reduzieren, die wir auf die Festplatte schreiben, verlängern wir die Lebensdauer der SSD.

Auch wenn die Komprimierung hilft, reicht sie leider für größere Datenmengen möglicherweise nicht aus. Ein weiterer Schritt wäre, nach etwas anderem als InnoDB zu suchen.

MyRocks

MyRocks ist eine für MySQL und MariaDB verfügbare Speicher-Engine, die auf einem anderen Konzept als InnoDB basiert. Mein Kollege Sebastian Insausti hat einen netten Blog über die Verwendung von MyRocks mit MariaDB. Das Wesentliche ist, dass MyRocks aufgrund seines Designs (es verwendet Log Structured Merge, LSM) in Bezug auf die Komprimierung deutlich besser ist als InnoDB (das auf der B + Tree-Struktur basiert). MyRocks ist darauf ausgelegt, große Datenmengen zu verarbeiten und die Anzahl der Schreibvorgänge zu reduzieren. Es hat seinen Ursprung bei Facebook, wo die Datenmengen groß und die Anforderungen an den Zugriff auf die Daten hoch sind. Daher ist SSD-Speicher - in einem so großen Maßstab ist jeder Komprimierungsgewinn enorm. MyRocks kann sogar eine bis zu 2-mal bessere Komprimierung als InnoDB liefern (was bedeutet, dass Sie die Anzahl der Server um zwei reduzieren). Es wurde auch entwickelt, um die Schreibverstärkung (Anzahl der Schreibvorgänge, die erforderlich sind, um eine Änderung des Zeileninhalts zu verarbeiten) zu reduzieren – es erfordert 10x weniger Schreibvorgänge als InnoDB. Dies reduziert natürlich die E/A-Last, aber, was noch wichtiger ist, es verlängert die Lebensdauer einer SSD um das Zehnfache im Vergleich zur Handhabung der gleichen Last mit InnoDB). Aus Performance-Sicht gilt:Je kleiner das Datenvolumen, desto schneller der Zugriff, daher können solche Speicher-Engines auch dazu beitragen, die Daten schneller aus der Datenbank zu bekommen (obwohl dies beim Design von MyRocks nicht die höchste Priorität hatte).

Spaltendatenspeicher

Zugehörige Ressourcen ClusterControl Performance Management Understanding the Effects of High Latency in High Availability MySQL and MariaDB Solutions MySQL Performance Cheat Sheet

Irgendwann können wir nur noch zugeben, dass wir solche Datenmengen mit MySQL nicht bewältigen können. Sicher, Sie können es teilen, Sie können verschiedene Dinge tun, aber irgendwann macht es einfach keinen Sinn mehr. Es ist an der Zeit, nach weiteren Lösungen zu suchen. Eine davon wäre die Verwendung von spaltenförmigen Datenspeichern – Datenbanken, die mit Blick auf Big-Data-Analysen entwickelt wurden. Sicher, sie werden bei OLTP-Datenverkehr nicht helfen, aber Analysen sind heutzutage ziemlich Standard, da Unternehmen versuchen, datengesteuert zu sein und Entscheidungen auf der Grundlage exakter Zahlen und nicht zufälliger Daten zu treffen. Es gibt zahlreiche spaltenförmige Datenspeicher, aber wir möchten hier zwei davon erwähnen. MariaDB AX und ClickHouse. Wir haben ein paar Blogs, die erklären, was MariaDB AX ist und wie MariaDB AX verwendet werden kann. Was wichtig ist, MariaDB AX kann in Form eines Clusters hochskaliert werden, wodurch die Leistung verbessert wird. ClickHouse ist eine weitere Option zum Ausführen von Analysen – ClickHouse kann einfach so konfiguriert werden, dass es Daten aus MySQL repliziert, wie wir in einem unserer Blogbeiträge besprochen haben. Es ist schnell, es ist kostenlos und es kann auch verwendet werden, um einen Cluster zu bilden und Daten für eine noch bessere Leistung zu fragmentieren.

Schlussfolgerung

Wir hoffen, dass Ihnen dieser Blogbeitrag einen Einblick gegeben hat, wie große Datenmengen in MySQL oder MariaDB gehandhabt werden können. Glücklicherweise stehen uns einige Optionen zur Verfügung, und wenn wir es nicht wirklich zum Laufen bringen können, gibt es schließlich gute Alternativen.