Mysql
 sql >> Datenbank >  >> RDS >> Mysql

Erstellen Sie einen Index für eine riesige MySQL-Produktionstabelle ohne Tabellensperrung

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

https://dev.mysql.com/doc/refman/8.0/en/innodb-online-ddl-operations.html#online-ddl-index-syntax-notes

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, normalerweise zu einem Deadlock, der die INSERT-, UPDATE- oder DELETE-Anweisung für die Tabelle abbrach.

[2015] Aktualisieren von Tabellenindizes blockiert Schreibvorgänge in MySQL 5.5

Aus der obigen Antwort:

"Wenn Sie eine Version größer als 5.1 verwenden, werden Indizes erstellt, während die Datenbank online ist. Machen Sie sich also keine Sorgen, Sie werden die Nutzung 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.)

Das Ausführen von UPDATE-Operationen an einer Tabelle wird BLOCKIEREN während der Index erstellt wird. MySQL ist in dieser Hinsicht (und in einigen anderen Dingen) wirklich, wirklich dumm.

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 Beenden der Indexaktualisierung benötigt werden):

 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

Aktualisierung des MySQL-Schemas ohne Ausfallzeit

Bisher gibt es nur eine Methode, die ich kenne, um ein MySql-Schema zu aktualisieren und keinen Verfügbarkeitsausfall zu erleiden. Kreismeister:

  • Auf Master A läuft Ihre MySQL-Datenbank
  • Bringen Sie Master B in Betrieb und lassen Sie ihn Schreibvorgänge von Master A replizieren (B ist ein Slave von A)
  • Führen Sie das Schema-Update auf Master B durch. Es wird während des Upgrades zurückfallen
  • Lassen Sie Meister B aufholen. Invariante:Ihre Schemaänderung MUSS in der Lage sein, Befehle zu verarbeiten, die von einem Downversion-Schema repliziert wurden. Indizierungsänderungen qualifizieren sich. Einfache Spaltenzusätze sind normalerweise geeignet. Spalte entfernen? wahrscheinlich nicht.
  • Wechsle alle Clients ATOMISCH von Master A zu Master B. Wenn du auf Nummer sicher gehen willst (vertrau mir, das tust du), solltest du sicherstellen, dass der letzte Schreibvorgang an A VORHER an B repliziert wird B nimmt seinen ersten Schreibvorgang vor. Wenn Sie gleichzeitiges Schreiben auf 2+ Master zulassen, ... verstehen Sie die MySQL-Replikation auf einer TIEFEN Ebene besser, oder Sie steuern auf eine Welt voller Schmerzen zu. Extreme Schmerzen. Haben Sie zum Beispiel eine Spalte, die AUTOINCREMENT ist??? Sie sind am Arsch (es sei denn, Sie verwenden gerade Zahlen für einen Master und ungerade Zahlen für den anderen). Vertrauen Sie der MySQL-Replikation NICHT, dass sie „das Richtige tut“. Es ist NICHT schlau und wird Sie nicht retten. Es ist nur etwas weniger sicher, als binäre Transaktionsprotokolle von der Befehlszeile zu kopieren und sie von Hand abzuspielen. Dennoch kann das Trennen aller Clients vom alten Master und das Umschalten auf den neuen Master in Sekunden erledigt werden, viel 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 Meister A und aktualisieren Sie sein Schema, sodass er Ihr neuer sekundärer Meister wird, der bereit ist, die Macht zu übernehmen, falls Ihr primärer Meister (jetzt Meister B) die Macht verliert oder einfach aufhört und auf Ihnen stirbt.
  • li>

Eine einfache Möglichkeit, das Schema zu aktualisieren, ist dies nicht. In einer seriösen Produktionsumgebung praktikabel; ja ist es. Bitte, bitte, bitte, wenn es einen einfacheren Weg gibt, einen Index zu einer MySQL-Tabelle hinzuzufügen, ohne Schreibvorgänge zu blockieren, lassen Sie es mich wissen.

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

Perconas pt-online-Schema-Änderung

Der Artikel Ich habe oben verlinkte Gespräche über ein Tool, pt -Online-Schema-Änderung , das geht so:

  • Erstelle eine neue Tabelle mit derselben Struktur wie das Original.
  • Schema in neuer Tabelle aktualisieren.
  • Fügen Sie einen Auslöser für die Originaltabelle hinzu, damit Änderungen mit der Kopie synchronisiert bleiben
  • Zeilen stapelweise aus Originaltabelle kopieren.
  • Schieben Sie die ursprüngliche Tabelle aus dem Weg und ersetzen Sie sie durch eine neue Tabelle.
  • Alte Tabelle löschen.

Ich selbst habe das Tool noch nie ausprobiert. YMMV

RDS

Ich verwende derzeit MySQL über Amazons RDS . Es ist ein wirklich raffinierter Dienst, der MySQL zusammenfasst und verwaltet, sodass Sie neue Lesereplikate mit einer einzigen Schaltfläche hinzufügen und die Datenbank über Hardware-SKUs hinweg transparent aktualisieren können. Es ist wirklich bequem. Sie erhalten keinen SUPER-Zugriff auf die Datenbank, also können Sie nicht direkt mit der Replikation schrauben (ist dies ein Segen oder Fluch?). Sie können jedoch Lesereplikat-Werbung um Ihre Schemaänderungen auf einem schreibgeschützten Slave vorzunehmen, und stufen Sie diesen Slave dann zu Ihrem neuen Master hoch. Genau der gleiche Trick, den ich oben beschrieben habe, nur viel einfacher auszuführen. Sie tun immer noch nicht viel, um Ihnen bei der Umstellung zu helfen. Sie müssen Ihre App neu konfigurieren und neu starten.