Ist es möglich (und wie), eine große MyISAM-Tabelle in InnoDB zu konvertieren, ohne die Anwendung offline zu schalten? Sie müssen pro Sekunde ein paar Zeilen in diese Tabelle einfügen, können sie jedoch für ca. 2 Minuten anhalten.
Offensichtlich wird ALTER TABLE ... engine = innodb nicht funktionieren. Daher hatte ich den Plan, eine neue Tabelle mit der innodb-Engine zu erstellen und den Inhalt in diese zu kopieren. Und am Ende setzen Sie den Anwendungsprotokoll-Thread und RENAME TABLE aus.
Leider führt selbst das Kopieren in kleinen Stapeln von 100 Zeilen nach einiger Zeit zu einer erheblichen Verzögerung.
Bearbeiten : Bestehende Zeilen werden nie geändert, diese Tabelle wird für die Protokollierung verwendet.
Antworten:
Erstellen Sie ein Master-Master-Setup wie folgt:
logTable
logTable_new
Als innodb erstellenINSERT INTO logTable_new SELECT * FROM logTable
(psuedocode) auf MasterB aus, wodurch die Replikation an MasterA gesendet wirdlogTable_new
MasterA die Synchronisierung abgeschlossen hat, tauschen Sie die Tabellen ausquelle
Angesichts der Einschränkung von:
Wenn Sie während der Protokollierung eine gute Möglichkeit haben, eine Markierung zu setzen, damit Sie feststellen können, wann Sie den Vorgang starten, können Sie Protokolle erneut anwenden oder die Protokolle in eine Textdatei schreiben Sie können sie später mit einnehmen
LOAD DATA INFILE
Ein Teil des Problems besteht darin, dass das Schreiben in kleineren Stapeln bedeutet, dass die Indizes immer wieder neu berechnet werden müssen. Es ist besser, wenn Sie alles auf einmal ausführen. Dies kann jedoch zu einer spürbaren Verzögerung des Systems führen. Sie müssen dies jedoch nicht auf Ihrem Produktionsserver tun.
LOAD DATA INFILE
).quelle
Fügen Sie eine Verzögerung zwischen den einzelnen Stapeln hinzu, oder führen Sie die Aktualisierungen nur stapelweise aus und führen Sie jeden Stapel direkt nach dem vorherigen aus?
Wenn ja, dann schreiben Sie die Konvertierung in Ihre Lieblingssprache mit etwas wie:
Dies sollte sicherstellen, dass die Konvertierung nicht mehr als die Hälfte der Serverkapazität beansprucht, selbst wenn Unterschiede in der Auslastung berücksichtigt werden, da die Systemnutzung mit der Zeit variiert.
Oder wenn Sie so viel Zeit wie möglich verwenden möchten, während der Dienst relativ inaktiv ist, sich aber zurückzieht (möglicherweise für längere Zeit pausiert), wenn die Datenbank für ihre Benutzer etwas Arbeit erledigen muss, ersetzen Sie
sleep for as long as the update took
durchif the server's load is above <upper measure>, sleep for some seconds then check again, loop around the sleep/check until the load drops below <lower measure>
. Dies bedeutet, dass es in ruhigen Zeiten vorwärtsdampfen kann, aber vollständig pausiert, wenn der Server mit seiner normalen Arbeitsauslastung beschäftigt ist. Die Bestimmung der Last hängt von Ihrem Betriebssystem ab - unter Linux und ähnlichen Bedingungen sollte der 1-Minuten-Durchschnittswert für die Last von/proc/loadavg
oder die Ausgabe vonuptime
ausreichen.<lower measure>
und<upper measure>
kann derselbe Wert sein, obwohl es in Steuerelementen wie diesem üblich ist, einen Unterschied zu haben, damit Ihr Prozess nicht weiter startet und dann sofort pausiert, da sein eigener Neustart einen Einfluss auf das Lastmaß hat.Dies funktioniert natürlich nicht für Tabellen, in denen alte Zeilen möglicherweise geändert werden, aber für eine Protokolltabelle wie die von Ihnen beschriebene.
In diesem Fall sollten Sie die übliche Vorgehensweise beim Erstellen von Indizes ignorieren, nachdem Sie die neue Tabelle ausgefüllt haben. Das ist in der Tat effizienter, wenn Sie möchten, dass die Dinge so schnell wie möglich ablaufen (was sich verdammt auf den Rest des Systems auswirkt), aber in diesem Fall möchten Sie nicht, dass am Ende des Prozesses eine große Lastschwemme entsteht wie bei Indizes werden vollständig auf einmal erstellt, da dies ein Vorgang ist, den Sie nicht unterbrechen können, wenn etwas los ist.
quelle
Würde so etwas funktionieren?
$auto_increment
in Ihrer Protokollierungstabellemytable
nicht ändert).$auto_increment
Wert mitSHOW TABLE STATUS LIKE 'mytable'
.CREATE TABLE mytable_new LIKE mytable
ALTER TABLE mytable_new AUTO_INCREMENT=$auto_increment ENGINE=Innodb
RENAME TABLE mytable TO mytable_old, mytable_new TO mytable
INSERT INTO mytable SELECT * FROM mytable_old
.Sie können Schritt 7 in Stapeln oder in einer Anweisung ausführen, da die normale Protokollierung nicht blockiert werden sollte.
quelle