132

~5M 行の MySQL テーブルにインデックスを作成する必要があります。これは実稼働テーブルであり、CREATE INDEX ステートメントを実行すると、すべてが完全にブロックされるのではないかと心配しています...

挿入と選択をブロックせずにそのインデックスを作成する方法はありますか?

システムを停止してインデックスを作成し、再起動する必要はありません。

4

4 に答える 4

148

[2017]アップデート:MySQL5.6はオンラインインデックスアップデートをサポートしています

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

MySQL 5.6以降では、インデックスが作成または削除されている間、テーブルは読み取りおよび書き込み操作に引き続き使用できます。CREATEINDEXまたはDROPINDEXステートメントは、テーブルにアクセスしているすべてのトランザクションが完了した後にのみ終了するため、インデックスの初期状態はテーブルの最新の内容を反映します。以前は、インデックスの作成または削除中にテーブルを変更すると、通常、テーブルのINSERT、UPDATE、またはDELETEステートメントをキャンセルするデッドロックが発生していました。

[2015]テーブルインデックスの更新はMySQL5.5で書き込みをブロックします

上記の答えから:

「データベースがオンラインのときに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のスキーマを更新する

これまでのところ、MySqlスキーマを更新し、可用性が停止しないようにする方法は1つしかありません。サーキュラーマスター:

  • マスターAにはMySQLデータベースが実行されています
  • マスターBを稼働させ、マスターAからの書き込みを複製します(BはAのスレーブです)
  • マスターBでスキーマの更新を実行します。アップグレード中に遅れます
  • マスターBに追いつきましょう。不変:スキーマの変更は、ダウンバージョンスキーマから複製されたコマンドを処理できる必要があります。インデックスの変更は適格です。通常、単純な列の追加が適格です。列を削除しますか?おそらくそうではありません。
  • すべてのクライアントをマスターAからマスターBにアトミックにスワップします。安全を確保したい場合(信頼してください)、Aへの最後の書き込みがBに複製されることを確認する必要がありますBが最初の書き込みを行います。2+マスターへの同時書き込みを許可すると、... DEEPレベルでのMySQLレプリケーションをよりよく理解するか、苦痛の世界に向かいます。極度の痛み。同様に、AUTOINCREMENTである列がありますか?あなたは困惑しています(一方のマスターに偶数を使用し、もう一方のマスターにオッズを使用しない限り)。「正しいことをする」ためにMySQLレプリケーションを信頼しないでください。それは賢くなく、あなたを救うことはありません。コマンドラインからバイナリトランザクションログをコピーして手動で再生するよりも、少し安全性が低くなります。それでも、すべてのクライアントを古いマスターから切断して新しいマスターに切り替えることは、数時間のスキーマのアップグレードを待つよりもはるかに高速で、ほんの数秒で実行できます。
  • これでマスターBが新しいマスターになります。新しいスキーマがあります。人生は素晴らしい。ビールを飲む; 最悪の事態は終わりました。
  • マスターAでこのプロセスを繰り返し、スキーマをアップグレードして、彼が新しいセカンダリマスターになるようにします。これにより、プライマリマスター(現在はマスターB)の電源が切れたり、電源が切れて死亡した場合に引き継ぐことができます。

スキーマを更新する簡単な方法はそうではありません。深刻な実稼働環境で実行可能。はい、そうです。書き込みをブロックせずにMySQLテーブルにインデックスを追加する簡単な方法がある場合は、お知らせください。

グーグルは私を同様のテクニックを説明するこの記事に導きます。さらに良いことに、彼らは手順の同じ時点で飲むことを勧めています(私は記事を読む前に私の答えを書いたことに注意してください)!

Perconaのpt-online-schema-change

上でリンクした記事では、次のように機能するツールpt-online-schema-changeについて説明しています。

  • 元のテーブルと同じ構造の新しいテーブルを作成します。
  • 新しいテーブルのスキーマを更新します。
  • 元のテーブルにトリガーを追加して、変更がコピーと同期し続けるようにします
  • 元のテーブルから行をバッチでコピーします。
  • 元のテーブルを邪魔にならない場所に移動し、新しいテーブルと交換します。
  • 古いテーブルを削除します。

私は自分でツールを試したことがありません。YMMV

RDS

私は現在、AmazonのRDSを介してMySQLを使用しています。これは、MySQLをまとめて管理する非常に優れたサービスであり、ボタン1つで新しいリードレプリカを追加し、ハードウェアSKU全体でデータベースを透過的にアップグレードできます。本当に便利です。データベースへのSUPERアクセスを取得できないため、レプリケーションを直接失敗させることはできません(これは祝福ですか、それとも呪いですか?)。ただし、リードレプリカプロモーションを使用して、読み取り専用スレーブでスキーマを変更し、そのスレーブを新しいマスターになるようにプロモートすることができます。上で説明したのとまったく同じトリックですが、実行が非常に簡単です。彼らはまだカットオーバーであなたを助けるために多くをしていません。アプリを再構成して再起動する必要があります。

于 2013-01-10T00:28:37.253 に答える
20

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から

于 2016-03-17T14:56:30.283 に答える
3

pt-online-schema-change は、移行によってサイトがダウンしないことを本当に確認したい場合の方法です。

上記のコメントで書いたように、本番環境で pt-online-schema-change を使用した経験がいくつかあります。2,000 万以上のレコードのメイン テーブルとマスター -> 2 つの読み取り専用レプリケーション スレーブがあります。新しい列の追加、文字セットの変更、いくつかのインデックスの追加など、pt-online-schema-change を使用して少なくとも数十回の移行を行いました。移行期間中も大量のトラフィックを処理していますが、問題は発生していません。もちろん、本番環境で実行する前に、すべてのスクリプトを徹底的にテストする必要があります。

pt-online-schema-change がデータを 1 回コピーするだけで済むように、変更を 1 つのスクリプトにまとめようとしました。また、データが失われるため、列名の変更には十分注意してください。ただし、インデックスを追加しても問題ありません。

于 2015-09-03T15:53:19.620 に答える