sql >> データベース >  >> RDS >> Mysql

テーブルをロックせずに巨大なMySQL本番テーブルにインデックスを作成する

    [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操作を実行すると、 BLOCK インデックスの作成中。 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
    

    出力(インデックスの更新を完了するのにかかる約400ミリ秒の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アクセスを取得できないため、レプリケーションを直接失敗させることはできません(これは祝福ですか、それとも呪いですか?)。ただし、レプリカプロモーションを読む 読み取り専用スレーブでスキーマを変更してから、そのスレーブを新しいマスターに昇格させます。上で説明したのとまったく同じトリックですが、実行が非常に簡単です。彼らはまだカットオーバーであなたを助けるために多くをしていません。アプリを再構成して再起動する必要があります。



    1. WindowsからMySQL5.7を完全に削除する方法

    2. PostgreSQL:ユーザーレベルでsearch_pathを設定するにはどうすればよいですか?

    3. MySQL:LIKEの逆バージョンとは何ですか?

    4. SQLServerのタイムスタンプ列を日時形式に変換する方法