数時間オフラインにならずに、66,862,521行のテーブルをMyISAMからInnoDBに変換するにはどうすればよいですか?


18

アプリケーションをオフラインにすることなく、巨大なMyISAMテーブルをInnoDBに変換することは可能ですか?そのテーブルに毎秒数行を挿入する必要がありますが、約2分間中断することが可能です。

明らかにALTER TABLE ... engine = innodbは機能しません。そのため、innodbエンジンを使用して新しいテーブルを作成し、その中にコンテンツをコピーする計画がありました。最後に、アプリケーションログスレッドとRENAME TABLEを一時停止します。

残念ながら、100行の小さなバッチでコピーを行っても、しばらくするとかなりの遅れが生じます。

編集:既存の行が変更されることはありません。このテーブルはロギングに使用されます。



3
まあ、その質問は会話時間を最小限にすることです。会話に数日または数週間かかるかどうかは気にしません。ただし、アプリケーションのダウンタイムを必要とせず、顕著な遅延を発生させることなく、バックグラウンドで動作する必要があります。
ヘンドリックブルーマーマン

回答:


15

次のようにマスター-マスターセットアップを作成します。

  • 2番目のマスターMasterBを作成します
  • MasterBは、 logTable
  • logTable_newinnodbとして作成
  • INSERT INTO logTable_new SELECT * FROM logTableMasterBで(psuedocode)を実行し、MasterAに複製を送信します
  • ときlogTable_newMasterAに同期、テーブルスワップアウトを終了

10

次の制約がある場合:

会話に数日または数週間かかるかどうかは気にしません。ただし、アプリケーションのダウンタイムを必要とせず、顕著な遅延を生じることなく、バックグラウンドで動作する必要があります

ロギングを行っているときに、プロセスを開始する時点でわかるようにマーカーを設定する良い方法があれば、ログを再適用したり、ログをテキストファイルに書き出すことができます。後でそれらを摂取できます LOAD DATA INFILE

問題の一部は、より小さなバッチで記述すると、インデックスを何度も再計算する必要があることを意味します。一度にすべて実行する方が良いですが、これによりシステム上で「顕著な」遅延が発生する可能性があります..実稼働サーバーで実行する必要はありません。

  1. ロギングを一時停止するか、マーカーを設定して、後でこの時点からログを再適用できるようにします。
  2. MyISMテーブルを別のシステムにコピーします
  3. もう一方のシステムで、別の名前でInnoDBテーブルを作成し、データを移行します (ダンプして使用するとより高速になる場合がありますLOAD DATA INFILE
  4. InnoDBテーブルを元のシステムにコピーして戻します
  5. ロギング用に別のマーカーを設定します。
  6. 最後の2つのマーカーの間からすべてのログを新しいテーブルに再適用します。
  7. (手順6が数秒程度かかるまで、手順6で1分以上かかった場合は手順5と6を繰り返します)
  8. テーブルを交換します(古いテーブルをtable_BACKUPに、新しいテーブルを古いテーブルの名前に変更します)
  9. 最後のマーカー以降のログをキャッチします。

9

残念ながら、100行の小さなバッチでコピーを行っても、しばらくするとかなりの遅れが生じます。

各バッチ間に遅延を追加しますか、それとも単に更新をバッチ処理し、前のバッチの直後に各バッチを実行しますか?

その場合は、次のようなものを使用して、お気に入りの言語で変換のスクリプトを作成してください。

repeat
    copy oldest 100 rows that haven't been copied yet to new table
    sleep for as long as that update took
until there are <100 rows unprocessed
stop logging service
move the last few rows
rename tables
restart logging
delete the old table when you are sure the conversion has worked

これにより、システムの使用が時間とともに変化するため、サーバーの処理能力の半分以上を変換に費やさずに、負荷の差を許容できます。

データベースは、そのユーザーのためのいくつかの作業を行う必要がある場合、またはあなたは、サービスが(潜在的に時間のかなりの長さのため一時停止)オフ比較的アイドルが、帰ってきたとき、できるだけ多くの時間として使用したい場合は、交換してくださいsleep for as long as the update tookif the server's load is above <upper measure>, sleep for some seconds then check again, loop around the sleep/check until the load drops below <lower measure>。これは、静かな時間に先に進むことができることを意味しますが、サーバーが通常のワークロードの実行でビジーになると完全に一時停止します。負荷の決定はOSに依存します-Linuxでは、同様の1分間の負荷平均値/proc/loadavgまたは出力がuptime行うべきです。<lower measure>そして<upper measure>、あなたのプロセスはその後すぐに起動負荷測定に影響を与えるために、独自の再起動を一時停止維持しないように違いを持っているために、このような制御では通常ですが、同じ値であってもよいです。

もちろん、これは古い行が変更される可能性のあるテーブルでは機能しませんが、説明したようなログテーブルでは問題なく機能します。

この場合、新しいテーブルにデータを入力した、インデックスを作成するという通常の知恵を無視する必要があります。物事を可能な限り高速にしたい場合(システムの残りの部分への影響を気にせず)本当に効率的ですが、この場合、プロセスの最後に大きな負荷がかかりたくないインデックスは一度に完全に作成されます。これは、忙しいときに一時停止できないプロセスだからです。


4

このようなものは機能しますか?

  1. ロギングを一時停止$auto_incrementします(したがって、ロギングテーブル上mytable は変更されません)。
  2. $auto_incrementを使用して値に注意してくださいSHOW TABLE STATUS LIKE 'mytable'
  3. CREATE TABLE mytable_new LIKE mytable
  4. ALTER TABLE mytable_new AUTO_INCREMENT=$auto_increment ENGINE=Innodb
  5. RENAME TABLE mytable TO mytable_old, mytable_new TO mytable
  6. 再度ログを有効にします。これで、Innodbテーブルにデータが入力され始めます。
  7. INSERT INTO mytable SELECT * FROM mytable_old

ステップ7は、通常のロギングをブロックしてはならないため、バッチまたは1つのステートメントで実行できます。


innodbがauto_incrementを処理する方法のために、それは依然としてブロックされます。デフォルトでは、innodbはauto_increment列に挿入するときにテーブルレベルのロックを取得し、挿入が完了するとすぐにロックを解除します。
ovais.tariq
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.