Ändern von Spalten sehr großer MySQL-Tabellen mit geringer oder keiner Ausfallzeit

18

Ich muss regelmäßig Änderungen an Tabellen in MySQL 5.1 vornehmen, hauptsächlich durch Hinzufügen von Spalten. Sehr einfach mit dem Befehl alter table. Aber meine Tabellen haben jetzt bis zu 40 Millionen Zeilen und sie wachsen schnell ... Also dauern diese Befehle zum Ändern von Tabellen mehrere Stunden. In ein paar Monaten werden sie vermutlich Tage brauchen.

Da ich amazon RDS verwende, kann ich nicht mit Slave-Servern spielen und dann zum Master befördern. Meine Frage ist also, ob es eine Möglichkeit gibt, dies mit minimalen Ausfallzeiten zu tun. Es macht mir nichts aus, dass eine Operation Stunden oder sogar Tage dauert, wenn Benutzer die Datenbank natürlich weiterhin verwenden können ... Können sie zumindest lesen, während Spalten hinzugefügt werden? Was passiert, wenn meine App versucht zu schreiben? Einfügen oder aktualisieren? Wenn es sofort ausfällt, ist das eigentlich nicht so schlimm. Wenn es nur hängt und Probleme für den Datenbankserver verursacht, ist das ein großes Problem.

Dies muss ein recht häufiges Problem bei der Skalierung sein. Jeder muss Spalten hinzufügen. Was wird normalerweise in einer Produktionsdatenbank getan? Slave -> Master Migration?

Update - Ich habe vergessen zu erwähnen, dass ich die innodb-Speicherengine verwende

apptree
quelle
1
Falls noch jemand nach einer Antwort sucht .. blog.staginginstance.com/… ^^
Coder anonym

Antworten:

10

Ich muss regelmäßig Änderungen an Tabellen in MySQL 5.1 vornehmen und dabei hauptsächlich Spalten hinzufügen.

Nicht. Nicht wirklich. Tu es einfach nicht. Es sollte eine sehr seltene Gelegenheit sein, wenn dies jemals notwendig ist.

Angenommen, Ihre Daten sind zu Beginn wirklich normalisiert, besteht der richtige Weg zur Lösung des Problems darin, eine neue Tabelle mit einer 1: 1-Beziehung zur Basistabelle hinzuzufügen (für die neue Tabelle nicht obligatorisch).

Das regelmäßige Hinzufügen von Spalten ist normalerweise ein Indikator für eine nicht normalisierte Datenbank. Wenn Ihr Schema nicht normalisiert ist, müssen Sie dieses Problem beheben.

Schließlich, wenn Ihr Schema wirklich, wirklich normalisiert ist und Sie wirklich, wirklich weiterhin Spalten hinzufügen müssen, dann:

  1. Stellen Sie sicher, dass die Datenbank eine Zeitstempelspalte enthält oder Replikationsprotokolle generiert
  2. Erstellen Sie eine Kopie (B) der Tabelle (A)
  3. füge die neuen Spalten zu B hinzu (dies wird immer noch mit myisam blockiert)
  4. Transaktionen deaktivieren
  5. benenne die ursprüngliche Tabelle (A) um als etwas anderes (backup)
  6. Benenne die neue Tabelle (B) mit dem Namen der ursprünglichen Tabelle (A) um
  7. Wiederholen Sie die Transaktionen ab dem Start des Vorgangs aus dem Replikationsprotokoll oder aus der Sicherungstabelle
  8. Transaktionen aktivieren.
symcbean
quelle
2
Vielen Dank für Ihre schrittweise Vorgehensweise. Ist es wirklich ungewöhnlich, Tabellen zu ändern? Ich verstehe, dass ich stattdessen eine weitere Tabelle mit der neuen Spalte hinzufügen kann (falls eine Spalte hinzugefügt werden muss) und die ursprüngliche große Tabelle in einer 1: 1-Beziehung referenzieren kann. Aber es scheint nicht richtig zu sein, 15 sehr große 1: 1-Tabellen zu haben, wenn sie alle in einer Tabelle sein sollten ... Die Abfrageleistung leidet dann natürlich auch, ganz zu schweigen von den Indexierungsproblemen. Ich bin kein Experte, aber meine Datenbank ist ziemlich normalisiert, und es scheint natürlich, dass ich regelmäßig Änderungen
vornehmen muss
2
"Ist es wirklich ungewöhnlich, Tabellen zu ändern?" - Ja.
Symcbean
1
Nein, aber man kann argumentieren, dass, wenn dies REGELMÄSSIG geschieht - nicht im Rahmen eines größeren Software-Upgrades -, jemand entlassen werden muss, um nicht zu erkennen, dass überhaupt alle Tabellen vorhanden sein sollten. Das Problem / der Trick ist hier "regelmäßig", nicht "alle paar Monate einmal".
TomTom
22
Als Entwickler, insbesondere einer, der in Start-ups und jungen Unternehmen arbeitet, konnte ich symcbean und @TomTom nicht weniger zustimmen. Dinge ändern sich, Produkte ändern sich, Geschäftsziele ändern sich und die Datenbankstruktur muss sich mit ihnen ändern. Um einen guten DBA-Service bereitzustellen, müssen Sie diese Änderungen mit "Ja" bestätigen und dann herausfinden, wie Sie sie effizient implementieren können. Stark normalisierte Datenbanken sind ein Konzept, das vor langer Zeit gestorben ist. Sie führen zu schlechter Leistung und langsamen Entwicklungszyklen.
pents90
4
Gelegentlich, um Tabellen zu ändern? Vielleicht in großen Unternehmen, aber in agilen Teams ändern sich die Anforderungen häufig ...
tibo
12

Ich musste das erst kürzlich tun. Was Amazon empfahl, war die Verwendung des Percona-Toolkits. Ich habe es heruntergeladen und konnte folgendes ausführen:

./pt-online-schema-change h=databasenameHostName,D=databasename,t=tablename --recursion-method=none --execute --user username --password password --alter "MODIFY someColumn newDataType"

und es funktioniert super. Hier erfahren Sie, wie viel Zeit in dem Prozess verbleibt.

Es erstellt tatsächlich eine neue Tabelle mit der neuen Spalte und kopiert dann die vorhandenen Daten. Darüber hinaus wird ein Trigger erstellt, sodass auch neue Daten in die neue Tabelle verschoben werden. Anschließend werden die Tabellen automatisch umbenannt, die alte Tabelle gelöscht, und Sie können mit der neuen Spalte arbeiten, und es treten keine Ausfallzeiten auf, während Sie auf die Aktualisierungen gewartet haben.

efreedom
quelle
Das Percona-Team hat eine kurze Beschreibung zur Aktivierung der Funktion log_bin_trust_function_creators über RDS-Parametergruppen (da SET GLOBAL log_bin_trust_function_creators = 1 nicht für RDS funktioniert), die vom pt-online-Schemaänderungstool benötigt wird. Weitere Details: percona.com/blog/2016/07/01/pt-online-schema-change-amazon-rds
user1652110
Es hat für mich
funktioniert
4

symcbean bietet einige solide Empfehlungen .

Um Ihre Frage zu beantworten, ist es am einfachsten und besten, mehrere Datenbanken zu replizieren, um die Auswirkungen zu verringern. Dual-Master mit einem geeigneten Failover-Verfahren zum Stoppen der Replikation auf dem aktiven Server, wodurch eine Änderung auf dem inaktiven Server ohne Beeinträchtigung des aktiven Servers möglich wird.

Sie können dies möglicherweise in einer einzelnen Live-Datenbank tun und die Auswirkungen auf ein Minimum reduzieren, indem Sie ein Verfahren anwenden, das dem in dieser Antwort beschriebenen ähnelt . Zugegebenermaßen ähnelt dies dem, was symcbean beschrieben hat, enthält jedoch technische Details. Sie können auch ein auto_increment-Feld verwenden und nicht nur einen Zeitstempel.

Wenn Ihre Datenmenge so groß wird, müssen Sie letztendlich auch die Archivierung zwischen OLTP- und OLAP- Datenbanken berücksichtigen . Ihr Transaktionsdatensatz muss nicht so groß sein, wenn Sie entsprechend gestalten.

Warner
quelle
2

Aus dem Handbuch: http://dev.mysql.com/doc/refman/5.1/en/alter-table.html

In den meisten Fällen erstellt ALTER TABLE eine temporäre Kopie der Originaltabelle. MySQL übernimmt die Änderung in die Kopie, löscht dann die ursprüngliche Tabelle und benennt die neue um. Während ALTER TABLE ausgeführt wird, kann die ursprüngliche Tabelle von anderen Sitzungen gelesen werden. Aktualisierungen und Schreibvorgänge in die Tabelle werden angehalten, bis die neue Tabelle fertig ist. Anschließend werden sie automatisch ohne fehlgeschlagene Aktualisierungen in die neue Tabelle umgeleitet.

Lesen wird also gut funktionieren. Schreibvorgänge werden angehalten, aber anschließend ausgeführt. Wenn Sie dies verhindern möchten, müssen Sie Ihre Software ändern.


quelle
Also habe ich das getan und die Teile meiner Website deaktiviert, die in die Tabelle schreiben, die ich gerade ändere. Bisher habe ich mehrere Ausnahmen "Wartezeit für Sperre überschritten; versuchen Sie, die Transaktion neu zu starten" erhalten, das ist nicht so schlimm. Allerdings waren sie auf REIN Leseoperationen ...
Apptree
0

Ich bin in einer ähnlichen Situation, in der ich 1 meiner Transaktionstabelle ändern muss, die fast 65 GB groß ist. Ich höre 2 Lösungen

  1. Benutze ALTER und lass es laufen (X Anzahl Stunden oder Tag)
  2. Stellen Sie sicher, dass die Datenbank eine Zeitstempelspalte enthält oder Replikationsprotokolle generiert
    • Erstellen Sie eine Kopie (B) der Tabelle (A)
    • füge die neuen Spalten zu B hinzu (dies wird immer noch mit myisam blockiert)
    • Transaktionen deaktivieren
    • benenne die ursprüngliche Tabelle (A) um als etwas anderes (backup)
    • Benenne die neue Tabelle (B) mit dem Namen der ursprünglichen Tabelle (A) um
user144107
quelle