変更したいInnoDBテーブルがあります。テーブルには〜8千万行あり、いくつかのインデックスを終了します。
列の1つの名前を変更し、さらにいくつかのインデックスを追加したいと思います。
alter table
、最速のソリューションですか?この時点で、私が気にしているのは速度です:)
ALTER TABLEを高速化する確実な方法の1つは、不要なインデックスを削除することです
新しいバージョンのテーブルをロードするための最初のステップは次のとおりです
_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
;
_
次の点に注意してください:
Source_persona_indexは、他の4つのインデックスの最初の列であるため、削除しました
Target_persona_indexは、他の2つのインデックスの最初の列なので削除しました
最初の2列もtarget_persona_relation_type_message_id_indexにあるため、target_persona_relation_type_indexを削除しました
OK不要なインデックスを処理します。カーディナリティが低いインデックスはありますか?これを確認する方法は次のとおりです。
次のクエリを実行します。
_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;
_
あなたの質問によると、約80,000,000行があります。経験則として、MySQL Query Optimizerは、選択された列のカーディナリティがテーブル行カウントの5%より大きい場合、インデックスを使用しません。この場合、4,000,000になります。
COUNT(DISTINCT sent_at)
> 4,000,000 の場合ALTER TABLE s_relations_new DROP INDEX sent_at_index;
_COUNT(DISTINCT message_id)
> 4,000,000 の場合ALTER TABLE s_relations_new DROP INDEX message_id_index;
_COUNT(DISTINCT target_object_id)
> 4,000,000 の場合ALTER TABLE s_relations_new DROP INDEX target_object_index;
_これらのインデックスの有用性または無用性が決定したら、データを再ロードできます
_#
# 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;
_
それだけですよね?いいえ!!!
Webサイトがずっと稼働している場合、s_relations_newのロード中にs_relationsに対してINSERTが実行されている可能性があります。欠けている行をどのように取得できますか?
S_relations_newで最大IDを見つけて、s_relationsからそのIDの後にすべてを追加します。テーブルが確実に凍結され、この更新のみに使用されるようにするには、s_relation_newに挿入された最後の行を取得するために、少しのダウンタイムが必要です。ここではあなたが何をすべきかです:
OSでmysqlを再起動して、root @ localhost以外の誰もログインできないようにします(TCP/IPを無効にします)。
_$ service mysql restart --skip-networking
_
次に、mysqlにログインし、最後の行をロードします。
_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;
_
次に、mysqlを通常どおり再起動します
_$ service mysql restart
_
ここで、mysqlを停止できない場合は、s_relationsでベイトアンドスイッチを実行する必要があります。 mysqlにログインして、以下を実行します。
_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;
_
試してみる !!!
警告:この操作に満足したら、できるだけ早く古いテーブルを削除できます。
_mysql> DROP TABLE s_relations_old;
_
正しい答えは、使用しているMySQLエンジンのバージョンによって異なります。
5.6+を使用している場合、名前の変更とインデックスの追加/削除は online で実行されます。つまり、すべてのテーブルのデータをコピーすることはありません。
ALTER TABLE
通常どおり、ほとんどの場合、名前の変更とインデックスの削除は瞬時に行われ、インデックスの追加はかなり高速になります(すべてのテーブルを一度に読み取るのと同じ速さ)。
5.1+を使用していて、InnoDBプラグインが有効になっている場合は、インデックスの追加/削除もオンラインになります。名前の変更については不明です。
古いバージョンを使用している場合、ALTER TABLE
は依然として最速ですが、すべてのデータが内部の一時テーブルに再挿入されるため、恐ろしく遅くなります。
最後に、神話を暴く時間です。残念ながら、回答にコメントするのに十分なカルマはありませんが、最も投票された回答を修正することが重要だと感じています。これは間違っています:
経験則として、MySQL Query Optimizerは、選択された列のカーディナリティがテーブル行カウントの5%より大きい場合、インデックスを使用しません
実際には 他の方法 です。
インデックスはfew行を選択するのに役立ちます。したがって、それらがhighカーディナリティを持っていることが重要です。同じ値。
Maria DB 10.1.12にも同じ問題があり、ドキュメントを読んだ後、「インプレース」操作を実行してテーブルのコピーを削除するオプションがあることがわかりました。このオプションを使用すると、変更テーブルは非常に高速になります。私の場合、それは:
alter table user add column (resettoken varchar(256),
resettoken_date date, resettoken_count int), algorithm=inplace;
これは非常に高速です。アルゴリズムオプションがないと、終了しません。
列の名前を変更するには、
ALTER TABLE tablename CHANGE columnname newcolumnname datatype;
正常であり、ダウンタイムは発生しません。
インデックスの場合、CREATE INDEXステートメントはテーブルをロックします。あなたが言ったようにそれが未使用のスレーブであるなら、それは問題ではありません。
他の1つのオプションは、適切な列名とインデックスを持つ真新しいテーブルを作成することです。次に、すべてのデータをそこにコピーしてから、一連の
BEGIN TRAN;
ALTER TABLE RENAME tablename tablenameold;
ALTER TABLE RENAME newtablename tablename;
DROP TABLE tablenameold;
COMMIT TRAN;
これにより、一時的に2倍のスペースを使用することを犠牲にして、ダウンタイムを最小限に抑えることができます。
私にもこの問題があり、次のSQLを使用しました。
/*on créé la table COPY SANS les nouveaux champs et SANS les FKs */
CREATE TABLE IF NOT EXISTS prestations_copy LIKE prestations;
/* on supprime les FKs de la table actuelle */
ALTER TABLE `prestations`
DROP FOREIGN KEY `fk_prestations_pres_promos`,
DROP FOREIGN KEY `fk_prestations_activites`;
/* on remet les FKs sur la table copy */
ALTER TABLE prestations_copy
ADD CONSTRAINT `fk_prestations_activites` FOREIGN KEY (`act_id`) REFERENCES `activites` (`id`) ON UPDATE NO ACTION ON DELETE NO ACTION,
ADD CONSTRAINT `fk_prestations_pres_promos` FOREIGN KEY (`presp_id`) REFERENCES `pres_promos` (`id`) ON UPDATE NO ACTION ON DELETE NO ACTION;
/* On fait le transfert des données de la table actuelle vers la copy, ATTENTION: il faut le même nombre de colonnes */
INSERT INTO prestations_copy
SELECT * FROM prestations;
/* On modifie notre table copy de la façon que l'on souhaite */
ALTER TABLE `prestations_copy`
ADD COLUMN `seo_mot_clef` VARCHAR(50) NULL;
/* on supprime la table actuelle et renome la copy avec le bon nom de table */
SET FOREIGN_KEY_CHECKS=0;
DROP TABLE prestations;
RENAME TABLE prestations_copy TO prestations;
SET FOREIGN_KEY_CHECKS=1;
私はそれが誰かを助けることを願っています
よろしく、
意志