it-swarm.com.de

Erstellen Sie einen Index für eine große MySQL-Produktionstabelle ohne Tabellensperre

Ich muss einen Index für eine MySQL-Tabelle mit ~ 5 Millionen Zeilen erstellen. Es ist eine Produktionstabelle, und ich fürchte einen vollständigen Block von allem, wenn ich eine CREATE INDEX-Anweisung ausführe ...

Gibt es eine Möglichkeit, diesen Index zu erstellen, ohne Einfügungen und Auswahlen zu blockieren?

Ich wundere mich nur, dass ich nicht aufhören muss, einen Index erstellen und mein System neu starten muss!

88
n0cturnal

[2017] Update: MySQL 5.6 unterstützt Online-Index-Updates

https://dev.mysql.com/doc/refman/5.6/de/innodb-create-index-overview.html

In MySQL 5.6 und höher bleibt die Tabelle für Lese- und Schreibvorgänge verfügbar, während der Index erstellt oder gelöscht wird. Die Anweisung CREATE INDEX oder DROP INDEX wird erst beendet, nachdem alle Transaktionen, die auf die Tabelle zugreifen, abgeschlossen sind, sodass der Anfangszustand des Index den neuesten Inhalt der Tabelle widerspiegelt. Bisher führte das Ändern der Tabelle, während ein Index erstellt oder gelöscht wurde, in der Regel zu einem Deadlock, durch den die INSERT-, UPDATE- oder DELETE-Anweisung für die Tabelle abgebrochen wurde.

[2015] Das Aktualisieren der Tabelle gibt an, dass in MySQL 5.5 Blöcke geschrieben wurden

Aus der obigen Antwort:

"Wenn Sie eine Version mit mehr als 5.1 Indizes verwenden, während die Datenbank online ist, müssen Sie sich keine Sorgen machen, dass Sie die Verwendung des Produktionssystems nicht unterbrechen."

Das ist falsch**** (Zumindest für MyISAM/InnoDB-Tabellen, die 99,999% der Leute da draußen verwenden. Clustered Edition ist anders.)

Wenn Sie UPDATE-Operationen für eine Tabelle ausführen, wird [~ # ~] blockiert [~ # ~] , während der Index erstellt wird. MySQL ist wirklich sehr, sehr dumm (und ein paar andere Dinge).

Testskript:

(   
  for n in {1..50}; do
    #(time mysql -uroot -e 'select  * from website_development.users where id = 41225\G'>/dev/null) 2>&1 | grep real;
    (time mysql -uroot -e 'update website_development.users set bio="" where id = 41225\G'>/dev/null) 2>&1 | grep real;
  done
) | cat -n &
PID=$!
sleep 0.05
echo "Index Update - START"
mysql -uroot website_development -e 'alter table users add index ddopsonfu (last_name, email, first_name, confirmation_token, current_sign_in_ip);'
echo "Index Update - FINISH"
sleep 0.05
kill $PID
time mysql -uroot website_development -e 'drop index ddopsonfu on users;'

Mein Server (InnoDB):

Server version: 5.5.25a Source distribution

Ausgabe (beachten Sie, wie die 6. Operation für die ~ 400 ms blockiert, die zum Abschließen der Indexaktualisierung erforderlich sind):

 1  real    0m0.009s
 2  real    0m0.009s
 3  real    0m0.009s
 4  real    0m0.012s
 5  real    0m0.009s
Index Update - START
Index Update - FINISH
 6  real    0m0.388s
 7  real    0m0.009s
 8  real    0m0.009s
 9  real    0m0.009s
10  real    0m0.009s
11  real    0m0.009s

Vs Leseoperationen, die nicht blockieren (tauschen Sie den Zeilenkommentar im Skript aus):

 1  real    0m0.010s
 2  real    0m0.009s
 3  real    0m0.009s
 4  real    0m0.010s
 5  real    0m0.009s
Index Update - START
 6  real    0m0.010s
 7  real    0m0.010s
 8  real    0m0.011s
 9  real    0m0.010s
...
41  real    0m0.009s
42  real    0m0.010s
43  real    0m0.009s
Index Update - FINISH
44  real    0m0.012s
45  real    0m0.009s
46  real    0m0.009s
47  real    0m0.010s
48  real    0m0.009s

Aktualisieren des MySQL-Schemas ohne Ausfallzeiten

Bisher kenne ich nur eine Methode, um ein MySql-Schema zu aktualisieren und keinen Verfügbarkeitsausfall zu erleiden. Zirkuläre Meister:

  • Auf Master A läuft Ihre MySQL-Datenbank
  • Bringen Sie Master B in Dienst und lassen Sie es Schreibvorgänge von Master A replizieren (B ist ein Slave von A)
  • Führen Sie die Schemaaktualisierung auf Master B durch. Sie bleibt während des Upgrades zurück
  • Lassen Sie Master B aufholen. Invariant: Ihre Schemaänderung MUSS in der Lage sein, Befehle zu verarbeiten, die aus einem Downversionsschema repliziert wurden. Änderungen an der Indexierung sind zulässig. Einfache Spaltenzusätze sind normalerweise geeignet. Spalte entfernen? wahrscheinlich nicht.
  • Tauschen Sie ATOMISCH alle Clients von Master A zu Master B aus. Wenn Sie sicher sein möchten (vertrauen Sie mir), sollten Sie sicherstellen, dass der letzte Schreibzugriff auf A nach B repliziert wird [~ # ~] bevor [~ # ~] B zum ersten Mal schreibt. Wenn Sie gleichzeitige Schreibvorgänge für mehr als 2 Master zulassen, ... verstehen Sie die MySQL-Replikation auf einer DEEP-Ebene besser, oder Sie stürzen sich in eine Welt voller Schmerzen. Extreme Schmerzen. Haben Sie eine Spalte, die AUTOINCREMENT ist? Sie sind geschraubt (es sei denn, Sie verwenden gerade Zahlen für einen Master und Quoten für den anderen). Vertrauen Sie der MySQL-Replikation NICHT, um "das Richtige zu tun". Es ist NICHT schlau und wird dich nicht retten. Es ist nur etwas weniger sicher als das Kopieren von binären Transaktionsprotokollen über die Befehlszeile und deren manuelle Wiedergabe. Das Trennen aller Clients vom alten Master und das Umschalten auf den neuen Master sind jedoch in Sekundenschnelle erledigt. Dies ist erheblich schneller als das Warten auf ein mehrstündiges Schema-Upgrade.
  • Jetzt ist Master B Ihr neuer Master. Sie haben das neue Schema. Das leben ist gut. Trink ein Bier; das Schlimmste ist vorbei.
  • Wiederholen Sie den Vorgang mit Master A, indem Sie sein Schema aktualisieren, sodass er Ihr neuer sekundärer Master wird und bereit ist, die Funktion zu übernehmen, falls Ihr primärer Master (jetzt Master B) die Stromversorgung verliert oder einfach aufgibt und an Ihnen stirbt.

Eine einfache Möglichkeit zum Aktualisieren des Schemas ist dies nicht. In einer seriösen Produktionsumgebung einsetzbar; ja ist es. Bitte, bitte, bitte, wenn es einen einfacheren Weg gibt, einen Index zu einer MySQL-Tabelle hinzuzufügen, ohne Schreibzugriffe zu blockieren, lassen Sie es mich wissen.

Googeln führte mich zu dieser Artikel , der eine ähnliche Technik beschreibt. Noch besser, sie raten zum Trinken an der gleichen Stelle im Verfahren (Beachten Sie, dass ich meine Antwort geschrieben habe, bevor ich den Artikel gelesen habe)!

Perconas pt-online-Schemaänderung

In dem oben verlinkten Artikel geht es um ein Tool pt-online-schema-change , das wie folgt funktioniert:

  • Erstellen Sie eine neue Tabelle mit derselben Struktur wie das Original.
  • Aktualisieren Sie das Schema für die neue Tabelle.
  • Fügen Sie der Originaltabelle einen Auslöser hinzu, damit die Änderungen mit der Kopie synchron bleiben
  • Kopieren Sie stapelweise Zeilen aus der Originaltabelle.
  • Bewegen Sie den Originaltisch aus dem Weg und ersetzen Sie ihn durch einen neuen Tisch.
  • Lass den alten Tisch fallen.

Ich habe das Tool selbst noch nie ausprobiert. YMMV

RDS

Ich verwende derzeit MySQL über Amazon RDS . Es ist ein wirklich raffinierter Dienst, der MySQL einschließt und verwaltet, mit dem Sie mit einem einzigen Knopf neue Lesereplikate hinzufügen und die Datenbank über Hardware-SKUs hinweg transparent aktualisieren können. Das ist sehr praktisch. Sie erhalten keinen SUPER-Zugriff auf die Datenbank, sodass Sie nicht direkt mit der Replikation beginnen können (ist dies ein Segen oder ein Fluch?). Sie können jedoch Read Replica Promotion verwenden, um Ihre Schemaänderungen an einem Nur-Lese-Slave vorzunehmen, und diesen Slave dann zu Ihrem neuen Master hochstufen. Genau der gleiche Trick, den ich oben beschrieben habe und der nur wesentlich einfacher auszuführen ist. Sie tun immer noch nicht viel, um Ihnen bei der Umstellung zu helfen. Sie müssen Ihre App neu konfigurieren und neu starten.

111
Dave Dopson

Wie dieser Blogpost umreißt, ist die InnoDB ALTER TABLE Mechanismus wurde für MySQL 5.6 komplett überarbeitet.

(Um einen exklusiven Überblick über dieses Thema zu erhalten, kann die MySQL-Dokumentation einen lesenswerten Nachmittag bieten.)

Um einen Index zu einer Tabelle hinzuzufügen, ohne dass eine Sperre für UPDATE/INSERT vorliegt, kann das folgende Anweisungsformat verwendet werden gebraucht:

ALTER TABLE my_table ADD INDEX my_table__idx (my_column), ALGORITHM=INPLACE, LOCK=NONE;
57
Drew

MySQL 5.6 Update (Februar 2013): Sie können jetzt Lese- und Schreibvorgänge ausführen, während ein Index erstellt wird, auch mit InnoDB-Tabellen - http://dev.mysql.com/doc/refman/5.6/en/innodb) -create-index-overview.html

In MySQL 5.6 und höher bleibt die Tabelle für Lese- und Schreibvorgänge verfügbar, während der Index erstellt oder gelöscht wird. Die Anweisung CREATE INDEX oder DROP INDEX wird erst beendet, nachdem alle Transaktionen, die auf die Tabelle zugreifen, abgeschlossen sind, sodass der Anfangszustand des Index den neuesten Inhalt der Tabelle widerspiegelt. Bisher führte das Ändern der Tabelle, während ein Index erstellt oder gelöscht wurde, in der Regel zu einem Deadlock, durch den die INSERT-, UPDATE- oder DELETE-Anweisung für die Tabelle abgebrochen wurde.

und:

In MySQL 5.6 wird diese Funktion allgemeiner: Sie können Tabellen lesen und schreiben, während ein Index erstellt wird, und viele weitere Arten von ALTER TABLE-Operationen können ausgeführt werden, ohne die Tabelle zu kopieren, ohne DML-Operationen zu blockieren oder beides. Daher bezeichnen wir in MySQL 5.6 und höher diesen Satz von Funktionen in der Regel als Online-DDL und nicht als Schnelle Indexerstellung.

from http://dev.mysql.com/doc/refman/5.6/de/glossary.html#glos_fast_index_creation

14
Eric Saboia

pt-online-schema-change ist der richtige Weg, wenn Sie wirklich sicherstellen möchten, dass die Migration die Site nicht zum Absturz bringt.

Wie ich im obigen Kommentar geschrieben habe, habe ich mehrere Erfahrungen mit pt-online-Schema-Änderungen in der Produktion. Wir haben unsere Haupttabelle mit über 20 Millionen Datensätzen und einen Master -> 2 schreibgeschützte Replikations-Slaves. Ich habe mindestens ein Dutzend Migrationen mit pt-online-schema-change durchgeführt, angefangen beim Hinzufügen einer neuen Spalte über das Ändern des Zeichensatzes bis hin zum Hinzufügen mehrerer Indizes. Wir bedienen auch während der Migrationszeit Tonnen von Verkehr und hatten keinen Schluckauf. Natürlich müssen Sie alle Skripte gründlich testen, bevor Sie mit der Produktion beginnen können.

Ich habe versucht, die Änderungen in einem Skript zusammenzufassen, damit die pt-online-Schemaänderung die Daten nur einmal kopieren muss. Gehen Sie beim Ändern des Spaltennamens sehr vorsichtig vor, da Sie sonst Ihre Daten verlieren. Das Hinzufügen eines Indexes sollte jedoch in Ordnung sein.

3
Alex Le