MySQLの大きなテーブルに列を追加する方法


12

私はPHP開発者なので、厳しくしないでください。約5.5GBの大きなテーブルがあります。私たちのPMは、新しい機能を実行するために新しいコラムを作成することにしました。テーブルはInnoDBなので、私が試したのは:

  1. 画面ロックでテーブルを変更します。約30時間かかりました。だから止めました。最初にすべてのトランザクションを終了しなかったためにミスをしましたが、2回目はマルチロックではありませんでした。ステータスはでしたcopy to tmp table

  2. このテーブルにもパーティションを適用する必要があるため、ダンプを作成し、名前を変更して、同じ名前と新しい構造のテーブルを作成することにしました。しかし、ダンプは厳密なコピーを作成しています(少なくとも他の何かは見つかりませんでした)。そこで、新しい列をダンプしsedてクエリを追加しました。しかし、いくつかの奇妙なエラーが始まりました。文字セットが原因だと思います。utf-8およびfileのテーブルは、後にus-asciiになりましたsed。そのため、データの30%でエラー(不明なコマンド '\' ')が発生しました。したがって、これも悪い方法です。

これを達成し、パフォーマンスを高速化する他のオプションは何ですか(PHPスクリプトで実行できますが、時間がかかります)。INSERT SELECTこの場合のパフォーマンスはどうなりますか。

事前に感謝します。

回答:


11

MySQL Workbenchを使用します。テーブルを右クリックし、[SQLエディターに送信]-> [ステートメントの作成]を選択できます。この方法では、テーブルの「プロパティ」を追加するのを忘れることはありません(CHARSETまたはを含むCOLLATE)。
この膨大なデータを使用して、使用するテーブルまたはデータ構造のいずれかをクリーンアップすることをお勧めします(優れたDBAが便利です)。可能でない場合:

  • テーブルの名前を変更し(ALTER)、CREATEWorkbenchから取得したスクリプトを使用して新しいテーブルを作成します。必要な新しいフィールドでそのクエリを拡張することもできます
  • 古いテーブルから新しいテーブルにデータを一括読み込みします。
    SET FOREIGN_KEY_CHECKS = 0;
    SET UNIQUE_CHECKS = 0;
    SET AUTOCOMMIT = 0;
    INSERT INTO new_table (fieldA, fieldB, fieldC, ..., fieldN)
       SELECT fieldA, fieldB, fieldC, ..., fieldN
       FROM old_table
    SET UNIQUE_CHECKS = 1;
    SET FOREIGN_KEY_CHECKS = 1;
    COMMIT;

    これにより、レコードごとにインデックスを作成するなどを回避できます。テーブルの「更新」は(データの量が膨大であるため)まだ遅いですが、これは私が考えることができる最も速い方法です。

    編集:この記事を読んで、上記のサンプルクエリで使用されるコマンドの詳細を確認してください;)

私のオプションは大丈夫です。そして、私は得ましたがSET NAMES utf8COLLATIONなぜデータの30%が壊れたのsedですか?バルクロードは最速になると思いますが、もっと不足しているものがあるかもしれません。ありがとうマーク
ineersa

1
@ineersaデータの破損には多くの理由があります。たとえば、すべての文字をサポートしていないエディターでファイルを開いて保存した場合です。または、ダンプからインポートしようとすると、データが破損します(バグがあり、ファイルを正しく読み取ることができません)。または、同じ男が一部のデータの一部を式(例: "james \ robin" == "\ r"の式)またはコマンドなどとして識別する場合があります。dev.mysql.com/doc/refman/5.6/en/mysqldump.html(またはMS SQL ServerのBCP)でさえも、そうではありません。間違ってあまりにも多くの時間...それを行く

はい、私はhex-blobで試しました。助けにはなりません。また、sed mysqlを使用した直後に、いくつかの名前(すべてではない)でコマンドとして\ 'を識別します。それは奇妙でバグが多い。今夜バルクロードを試みます。少なくとも10〜15時間で完了することを願っています。
ineersa

@ineersaはそれを期待しています。データの一部のみを追加することもできます。たとえば、データの10%を使用して、所要時間を確認し、トランザクション全体の見積もりを取得します。ただし、非常に大雑把な見積もりになります。キャッシュ/メモリ/その他がいっぱい/過負荷になると、処理が遅くなる可能性があります。

1
ありがとうマーク。素晴らしかった。さらに速く、ダンプから復元します。約5時間かかりました。
ineersa

5

sedのアイデアはまともな方法ですが、エラーやコマンドを実行しなければ、私たちはあなたを助けることができません。

ただし、大きなテーブルをオンラインで変更するよく知られた方法はpt-online-schema-changeです。このツールの機能の単純な見落としは、ドキュメントからコピーされています。

pt-online-schema-changeは、変更するテーブルの空のコピーを作成し、必要に応じて変更してから、元のテーブルから新しいテーブルに行をコピーすることで機能します。コピーが完了すると、元のテーブルを移動し、新しいテーブルに置き換えます。デフォルトでは、元のテーブルも削除されます。

このメソッドも完了するまでに時間がかかる場合がありますが、処理中に元のテーブルは完全に使用可能になります。


今晩、一括読み込みを試みます。うまくいかない場合は、おそらくこのツールが必要になります。エラーは、コマンドとしてsedを使用した後、いくつかのシンボルをinetifiengすることにより発生します。たとえば、'D\'agostini'エラーが発生しますunknown command '\''。ただし、常にではありませんが、30%の場合がそうです。それは奇妙でバグが多い。hex-blobダンプでも同じことが言えます。デレク、ありがとう。
ineersa

4

alter table add column, algorithm=inplace, lock=none テーブルをコピーしたりロックの影響を与えたりすることなく、MySQL 5.6テーブルを変更します。

昨日これをテストしたところ、70K行を280K行7パーティションテーブルに挿入し、各パーティションに10K行を挿入し、その間に5秒スリープして他のスループットを許可しました。

一括挿入を開始し、別のセッションalterでMySQL Workbenchで上記のオンラインステートメントを開始しましalterた。挿入前に終了し、2つの新しい列が追加されました。


1
なぜこの答えは投票数が増えないのですか?
fguillen

1

現在、巨大なテーブルを変更するための最良のオプションはおそらくhttps://github.com/github/gh-ostです

gh-ostは、MySQL用のトリガーレスオンラインスキーマ移行ソリューションです。テスト可能であり、一時性、動的な制御/再構成、監査、および多くの運用上の特典を提供します。

gh-ostは、移行中のマスターに軽いワークロードを生成し、移行したテーブルの既存のワークロードから切り離します。

既存のソリューションでの長年の経験に基づいて設計されており、テーブル移行のパラダイムを変更します。


1

Mydumper / Myloaderは、次のような操作に適したツールだと思います。毎日良くなっています。CPUを利用して、データを並行してロードできます:http : //www.percona.com/blog/2014/03/10/new-mydumper-0-6-1-release-offers-several-performance-and-ユーザビリティー機能/

私は数百ギガバイトのMySQLテーブルを数時間でロードすることに成功しました。

それは新しい列を追加することになると今、テーブル全体がメモリに渡ってMySQLのコピーとしてトリッキーであるTMPとエリアALTER TABLE...ロックなしで大規模なテーブルに対してそれらをオンラインで行うにはMySQLの5.6は、それがオンラインスキーマ変更を行うことができますと言いますが、私が管理していませんまだ競合。


-2

私は同じ問題を抱えていました。少しの回避策:

CREATE TABLE new_table SELECT * FROM oldtable;

new_tableから削除

ALTER TABLE new_table ADD COLUMN new_column int(11);

INSERT INTO new_table select *、0 from old_table

テーブルold_tableを削除します。テーブルの名前をnew_tableからold_tableに変更します。


create tableステートメントにwhere句を追加して、データを選択しないようにしませんか?また、テーブルを切り捨てることは、データを削除するよりも効率的です
Joe W

後で挿入する必要があるときに、削除する理由。ADD COLUMN自体でdefault = 0を定義できます。
user195280
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.