Eine sichere Möglichkeit, eine ALTER TABLE zu beschleunigen, besteht darin, unnötige Indizes zu entfernen
Hier sind die ersten Schritte zum Laden einer neuen Version der Tabelle
CREATE TABLE s_relations_new LIKE s_relations;
#
# Drop Duplicate Indexes
#
ALTER TABLE s_relations_new
DROP INDEX source_persona_index,
DROP INDEX target_persona_index,
DROP INDEX target_persona_relation_type_index
;
Bitte beachten Sie Folgendes:
Ich habe source_persona_index gelöscht, da dies die erste Spalte in 4 anderen Indizes ist
- unique_target_persona
- unique_target_object
- source_and_target_object_index
- source_target_persona_index
Ich habe target_persona_index gelöscht, weil es die erste Spalte in 2 anderen Indizes ist
- target_persona_relation_type_index
- target_persona_relation_type_message_id_index
Ich habe target_persona_relation_type_index gelöscht, da sich die ersten beiden Spalten auch in target_persona_relation_type_message_id_index befinden
OK Das sorgt für unnötige Indizes. Gibt es Indizes mit geringer Kardinalität? Hier ist der Weg, um das festzustellen:
Führen Sie die folgenden Abfragen aus:
SELECT COUNT(DISTINCT sent_at) FROM s_relations;
SELECT COUNT(DISTINCT message_id) FROM s_relations;
SELECT COUNT(DISTINCT target_object_id) FROM s_relations;
Ihrer Frage zufolge gibt es ungefähr 80.000.000 Zeilen. Als Faustregel gilt, dass das MySQL Query Optimizer keinen Index verwendet, wenn die Kardinalität der ausgewählten Spalten größer als 5% der Tabellenzeilenanzahl ist. In diesem Fall wären das 4.000.000.
- Wenn
COUNT(DISTINCT sent_at)
> 4.000.000
- dann
ALTER TABLE s_relations_new
DROP INDEX sent_at_index;
- Wenn
COUNT(DISTINCT message_id)
> 4.000.000
- dann
ALTER TABLE s_relations_new
DROP INDEX message_id_index;
- Wenn
COUNT(DISTINCT target_object_id)
> 4.000.000
- dann
ALTER TABLE s_relations_new
DROP INDEX target_object_index;
Sobald der Nutzen oder die Nutzlosigkeit dieser Indizes festgestellt wurde, können Sie die Daten neu laden
#
# Change the Column Name
# Load the Table
#
ALTER TABLE s_relations_new CHANGE sent_at sent_at_new int(11) DEFAULT NULL;
INSERT INTO s_relations_new SELECT * FROM s_relations;
Das war's, richtig? NOPE !!!
Wenn Ihre Website die ganze Zeit aktiv war, werden beim Laden von s_relations_new möglicherweise INSERTs gegen s_relations ausgeführt. Wie können Sie diese fehlenden Zeilen abrufen?
Suchen Sie die maximale ID in s_relations_new und hängen Sie alles nach dieser ID aus s_relations an. Um sicherzustellen, dass die Tabelle eingefroren ist und nur für dieses Update verwendet wird, müssen Sie eine kleine Ausfallzeit haben, um die letzten Zeilen zu erhalten, die in s_relation_new eingefügt wurden. Folgendes tun Sie:
Starten Sie mysql im Betriebssystem neu, damit sich nur root @ localhost anmelden kann (deaktiviert TCP / IP):
$ service mysql restart --skip-networking
Melden Sie sich als Nächstes bei MySQL an und laden Sie die letzten Zeilen:
mysql> SELECT MAX(id) INTO @maxidnew FROM s_relations_new;
mysql> INSERT INTO s_relations_new SELECT * FROM s_relations WHERE id > @maxidnew;
mysql> ALTER TABLE s_relations RENAME s_relations_old;
mysql> ALTER TABLE s_relations_new RENAME s_relations;
Starten Sie dann MySQL normal neu
$ service mysql restart
Wenn Sie MySQL nicht herunterfahren können, müssen Sie s_relations ködern und umschalten. Melden Sie sich einfach bei MySQL an und gehen Sie wie folgt vor:
mysql> ALTER TABLE s_relations RENAME s_relations_old;
mysql> SELECT MAX(id) INTO @maxidnew FROM s_relations_new;
mysql> INSERT INTO s_relations_new SELECT * FROM s_relations_old WHERE id > @maxidnew;
mysql> ALTER TABLE s_relations_new RENAME s_relations;
Versuche es !!!
CAVEAT: Sobald Sie mit dieser Operation zufrieden sind, können Sie den alten Tisch so schnell wie möglich löschen:
mysql> DROP TABLE s_relations_old;
SHOW CREATE TABLE tblname\G
zeigen Sie die Spalte an, die geändert werden muss, den Datentyp der Spalte und den neuen Namen für die Spalte.