web-dev-qa-db-ja.com

大きなmysqlテーブルにインデックスを追加する

テーブルがあります

| base_schedule_line_items |テーブルの作成base_schedule_line_items
id int(10)unsigned NOT NULL AUTO_INCREMENT、
installment int(10)unsigned NOT NULL、
on_date日付がNULLでない、
actual_date日付デフォルトNULL、
payment_type int(11)NOT NULL、
scheduled_principal_outstanding decimal(65,0)NOT NULL、
scheduled_principal_due decimal(65,0)NOT NULL、
scheduled_interest_outstanding decimal(65,0)NOT NULL、
scheduled_interest_due decimal(65,0)NOT NULL、
currency int(11)NOT NULL、
updated_at datetime NOT NULL DEFAULT '2013-01-06 14:29:16'、
created_at datetime NOT NULL DEFAULT '2013-01-06 14:29:16'、
loan_base_schedule_id int(10)符号なしNOT NULL、
lending_id int(10)符号なしNOT NULL、
reschedule tinyint(1)デフォルト '0'、
主キー(id)、
キーindex_base_schedule_line_items_loan_base_scheduleloan_base_schedule_id)、KEY index_bslt_spdscheduled_principal_due)、
キーindex_bslt_lendinglending_id)、
キーindex_bslt_actualdateactual_date)、
キーindex_bslt_spsilaloan_base_schedule_idscheduled_principal_duescheduled_interest_dueactual_date)、
キーindex_bslt_ondateon_date)、
キーindex_bslt_oaon_dateactual_date)、
キーindex_bslt_olon_dateloan_base_schedule_id)、
キーindex_bslt_olion_datelending_id
)ENGINE = InnoDB AUTO_INCREMENT = 30410126 DEFAULT CHARSET = utf8 |

このテーブルには3000万のレコードが含まれているので、さらに2つのインデックスを追加する必要があります。追加するのに数年かかるようです。

変更テーブルbase_schedule_line_items追加インデックスindex_bslt_sla(scheduled_principal_due、actual_date、lending_id);
代替テーブルbase_schedule_line_items add index index_bslt_ssla(scheduled_principal_due、scheduled_interest_due、lending_id、actual_date);

以下のクエリを使用してテーブルのサイズを調べました

SELECT table_name AS "Tables"、round(((data_length + index_length)/ 1024/1024)、2) "MB単位のサイズ" FROM information_schema.TABLES WHERE table_schema = "my_database_name";

結果は

base_schedule_line_items | 20111.00

データの長さを計算するためにこれを使用し、インデックスの長さは省略しました

SELECT table_name AS "Tables"、round(((data_length)/ 1024/1024)、2) "サイズ(MB)" FROM information_schema.TABLES WHERE table_schema = "my_database_name";

そして結果は

base_schedule_line_items | 9497.00

インデックス

KEY index_bslt_actualdate(actual_date)、
KEY index_bslt_spsila(loan_base_schedule_id、scheduled_principal_due、scheduled_interest_due、actual_date)、
KEY index_bslt_ondate(on_date)、
KEY index_bslt_oa(on_date、actual_date)、
KEY index_bslt_ol(on_date、loan_base_schedule_id)、
KEY index_bslt_oli(on_date、lending_id)

は私が追加したものですが、他の指標が追加された目的や目的は不明です。これはかなり大きなアプリケーションです。上記の2つのインデックスを追加する必要があります。これらは、selectステートメントを使用してレポートを抽出するのに役立ち、それらを追加するのが非常に難しいことがわかったためです。どんな助けでも大歓迎です

13
user2294477

大きなテーブルを変更する作業は、段階的に行われます。

  1. 必須フィールドとインデックスを使用して新しいテーブルを作成し、テストDBで言う(単なる構造)
  2. 既存のテーブルからデータをダンプし、テストDBに新しく作成されたテーブルにロードします
  3. 今あなたのダウンタイムを発表:)
  4. 名前を変更してテーブルを交換する-RENAME table ur_db.table_name to test.temp, test.table_name to ur_db.table_name, test.temp to test.table_name;これは、ほんの一瞬でアトミック操作になります。
  5. 新しく作成されたテーブル(ダンプしてからロードした後に来たレコード)に追加のレコードをロードします。このステップは、ステップ:3の前にも実行でき、ダウンタイムを短縮します。
  6. そしてあなたのシステムが戻ってきました

いくつかのメモ:

  1. このように情報スキーマを直接ヒットする必要はありません。SHOW TABLE STATUS from db like 'table_name'を使用してみてください
  2. 変更テーブルの速度は、多かれ少なかれI/O速度と関連しています。前回、上記の手順なしで直接変更テーブルを実行したとき、40GB以上のテーブルサイズがあり、約4時間かかりました。 20GBのデータに数年かかる場合、古いマシンで作業しています。
  3. index_bslt_ondate, index_base_schedule_line_items_loan_base_scheduleなどの不要なインデックスも削除します

これらの手順のいずれかについて説明が必要な場合はお知らせください。

編集:単純なpythonプロセスを自動化するスクリプト https://github.com/georgecj11/hotswap_mysql_table.git

16
georgecj11

pt-online-schema-change のようなツールを使用して、アプリケーションをブロックせずにインデックスを追加できます。基本的なロジックは次のとおりです。

  • 新しいインデックスでテーブルの空のコピーを作成する
  • 既存のテーブルにトリガーを追加して、テーブルにヒットした変更がテーブルのコピーに適用されるようにします*
  • 古いテーブルから新しいテーブルへの行のコピーを開始します
  • コピーが完了したら、テーブルを交換します
  • 古いテーブルを落とす

*テーブルに既存のトリガーがある場合、ツールは機能しません

スワッピングとドロップの動作は、ツールに渡されるオプションに基づいて調整できます。

また、外部キーには問題があるため、ツールのドキュメントを読んで、ツールの機能を完全に理解してください。

そしてもちろん、必要に応じて復元できるように、テーブルのバックアップがあることを確認するのが賢明です。

10
Derek Downey