~5M 行の MySQL テーブルにインデックスを作成する必要があります。これは実稼働テーブルであり、CREATE INDEX ステートメントを実行すると、すべてが完全にブロックされるのではないかと心配しています...
挿入と選択をブロックせずにそのインデックスを作成する方法はありますか?
システムを停止してインデックスを作成し、再起動する必要はありません。
~5M 行の MySQL テーブルにインデックスを作成する必要があります。これは実稼働テーブルであり、CREATE INDEX ステートメントを実行すると、すべてが完全にブロックされるのではないかと心配しています...
挿入と選択をブロックせずにそのインデックスを作成する方法はありますか?
システムを停止してインデックスを作成し、再起動する必要はありません。
MySQL 5.6以降では、インデックスが作成または削除されている間、テーブルは読み取りおよび書き込み操作に引き続き使用できます。CREATEINDEXまたはDROPINDEXステートメントは、テーブルにアクセスしているすべてのトランザクションが完了した後にのみ終了するため、インデックスの初期状態はテーブルの最新の内容を反映します。以前は、インデックスの作成または削除中にテーブルを変更すると、通常、テーブルのINSERT、UPDATE、またはDELETEステートメントをキャンセルするデッドロックが発生していました。
上記の答えから:
「データベースがオンラインのときに5.1を超えるバージョンを使用している場合は、インデックスが作成されます。したがって、本番システムの使用を中断することはありません。」
これは****FALSE****です(少なくともMyISAM / InnoDBテーブルの場合、99.999%の人が使用しています。ClusteredEditionは異なります。)
テーブルに対してUPDATE操作を実行すると、インデックスの作成中にブロックされます。MySQLは、これ(および他のいくつかのこと)について本当に、本当に愚かです。
テストスクリプト:
(
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;'
マイサーバー(InnoDB):
Server version: 5.5.25a Source distribution
出力(インデックスの更新を完了するのにかかる約400msの6番目の操作ブロックに注意してください):
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
ブロックしない読み取り操作(スクリプトの行コメントを入れ替える)との比較:
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
これまでのところ、MySqlスキーマを更新し、可用性が停止しないようにする方法は1つしかありません。サーキュラーマスター:
スキーマを更新する簡単な方法はそうではありません。深刻な実稼働環境で実行可能。はい、そうです。書き込みをブロックせずにMySQLテーブルにインデックスを追加する簡単な方法がある場合は、お知らせください。
グーグルは私を同様のテクニックを説明するこの記事に導きます。さらに良いことに、彼らは手順の同じ時点で飲むことを勧めています(私は記事を読む前に私の答えを書いたことに注意してください)!
上でリンクした記事では、次のように機能するツールpt-online-schema-changeについて説明しています。
私は自分でツールを試したことがありません。YMMV
私は現在、AmazonのRDSを介してMySQLを使用しています。これは、MySQLをまとめて管理する非常に優れたサービスであり、ボタン1つで新しいリードレプリカを追加し、ハードウェアSKU全体でデータベースを透過的にアップグレードできます。本当に便利です。データベースへのSUPERアクセスを取得できないため、レプリケーションを直接失敗させることはできません(これは祝福ですか、それとも呪いですか?)。ただし、リードレプリカプロモーションを使用して、読み取り専用スレーブでスキーマを変更し、そのスレーブを新しいマスターになるようにプロモートすることができます。上で説明したのとまったく同じトリックですが、実行が非常に簡単です。彼らはまだカットオーバーであなたを助けるために多くをしていません。アプリを再構成して再起動する必要があります。
MySQL 5.6 更新 (2013 年 2 月): InnoDB テーブルでもインデックスが作成されている間に読み取りおよび書き込み操作を実行できるようになりました - http://dev.mysql.com/doc/refman/5.6/en/innodb-create-index -overview.html
MySQL 5.6 以降では、インデックスが作成または削除されている間、テーブルは引き続き読み取りおよび書き込み操作に使用できます。CREATE INDEX または DROP INDEX ステートメントは、テーブルにアクセスしているすべてのトランザクションが完了した後にのみ終了するため、インデックスの初期状態はテーブルの最新の内容を反映しています。以前は、インデックスの作成中または削除中にテーブルを変更すると、通常、テーブルの INSERT、UPDATE、または DELETE ステートメントをキャンセルするデッドロックが発生しました。
と:
MySQL 5.6 では、この機能がより一般的になりました。インデックスの作成中にテーブルの読み取りと書き込みを行うことができ、さらに多くの種類の ALTER TABLE 操作を、テーブルをコピーせずに、DML 操作をブロックせずに、またはその両方で実行できます。したがって、MySQL 5.6 以降では、通常、この一連の機能を高速インデックス作成ではなくオンライン DDL と呼んでいます。
http://dev.mysql.com/doc/refman/5.6/en/glossary.html#glos_fast_index_creationから
pt-online-schema-change は、移行によってサイトがダウンしないことを本当に確認したい場合の方法です。
上記のコメントで書いたように、本番環境で pt-online-schema-change を使用した経験がいくつかあります。2,000 万以上のレコードのメイン テーブルとマスター -> 2 つの読み取り専用レプリケーション スレーブがあります。新しい列の追加、文字セットの変更、いくつかのインデックスの追加など、pt-online-schema-change を使用して少なくとも数十回の移行を行いました。移行期間中も大量のトラフィックを処理していますが、問題は発生していません。もちろん、本番環境で実行する前に、すべてのスクリプトを徹底的にテストする必要があります。
pt-online-schema-change がデータを 1 回コピーするだけで済むように、変更を 1 つのスクリプトにまとめようとしました。また、データが失われるため、列名の変更には十分注意してください。ただし、インデックスを追加しても問題ありません。