113

MySQL で ALTER TABLE ステートメントを実行すると、ステートメントが実行されている間、テーブル全体が読み取りロックされます (同時読み取りは許可されますが、同時書き込みは禁止されます)。大きなテーブルの場合、INSERT または UPDATE ステートメントが長時間ブロックされる可能性があります。プロセス全体でテーブルを更新できるように列を追加するなど、「ホットな変更」を行う方法はありますか?

ほとんどの場合、MySQL のソリューションに興味がありますが、MySQL で解決できない場合は、他の RDBMS に興味があります。

明確にするために、私の目的は、追加のテーブル列を必要とする新機能が本番環境にプッシュされるときのダウンタイムを回避することです。どのデータベース スキーマ時間の経過とともに変化します。これは単なる現実です。これらの変更によって必然的にダウンタイムが発生することを受け入れなければならない理由がわかりません。それはただ弱いです。

4

19 に答える 19

65

他の唯一のオプションは、多くの RDBMS システムがとにかく行うことを手動で行うことです...
- 新しいテーブルを作成します

次に、古いテーブルの内容を一度にチャンクでコピーできます。ソーステーブルでの INSERT/UPDATE/DELETE には常に注意を払ってください。(トリガーで管理できます。これにより速度が低下しますが、ロックではありません...)

終了したら、ソース テーブルの名前を変更してから、新しいテーブルの名前を変更します。できればトランザクションで。

終了したら、そのテーブルを使用するストアド プロシージャなどを再コンパイルします。実行計画は有効ではなくなる可能性があります。

編集:

この制限が少し貧弱であるというコメントがいくつかあります。そこで、なぜそうなのかを示すために、新しい視点を入れようと思いました...

  • 新しいフィールドを追加することは、すべての行で 1 つのフィールドを変更するようなものです。
  • フィールド ロックは、テーブル ロックは気にせず、行ロックよりもはるかに困難です。

  • 実際にディスク上の物理構造を変更しているので、すべてのレコードが移動します。
  • これは実際にはテーブル全体に対する UPDATE のようなものですが、より大きな影響があります...
于 2009-01-21T01:07:38.250 に答える
42

Percona は、これを可能にするpt-online-schema-changeというツールを作成しています。

基本的に、テーブルのコピーを作成し、新しいテーブルを変更します。新しいテーブルを元のテーブルと同期させるために、トリガーを使用して更新します。これにより、新しいテーブルがバックグラウンドで準備されている間に、元のテーブルにアクセスできます。

これは上記の Dems が推奨する方法に似ていますが、これは自動化された方法で行われます。

彼らのツールの中には、データベースへの接続という学習曲線を持っているものもありますが、それを理解してしまえば、それらは素晴らしいツールです。

元:

pt-online-schema-change --alter "ADD COLUMN c1 INT" D=db,t=numbers_are_friends
于 2012-10-10T19:23:37.780 に答える
31

2009年からのこの質問。現在、MySQLは解決策を提供しています:

オンライン DDL (データ定義言語)

DDL (主に ALTER TABLE) 操作中の InnoDB テーブルのパフォーマンス、同時実行性、および可用性を向上させる機能。詳細は、セクション14.11「InnoDB およびオンライン DDL」を参照してください。

詳細は操作の種類によって異なります。場合によっては、ALTER TABLE の進行中にテーブルを同時に変更できます。この操作は、テーブル コピーを実行せずに、または特別に最適化されたタイプのテーブル コピーを使用して実行できる場合があります。スペースの使用は、 innodb_online_alter_log_max_size 構成オプションによって制御されます。

テーブルへのアクセスを完全にブロックするか (LOCK=EXCLUSIVE 句)、クエリを許可するが DML は許可しないか (LOCK=SHARED 句)、完全なクエリと DML を許可するかを選択することで、DDL 操作中のパフォーマンスと同時実行性のバランスを調整できます。テーブルへのアクセス (LOCK=NONE 句)。LOCK 句を省略するか、LOCK=DEFAULT を指定すると、MySQL は操作のタイプに応じて可能な限り多くの同時実行を許可します。

テーブルの新しいコピーを作成するのではなく、可能な場合はインプレースで変更を実行することで、テーブルのコピーとセカンダリ インデックスの再構築に関連するディスク領域の使用量と I/O オーバーヘッドの一時的な増加を回避できます。

詳細については、MySQL 5.6 リファレンス マニュアル -> InnoDB およびオンライン DDLを参照してください。

オンラインDDLもMariaDBで利用できるようです

または、ALTER ONLINE TABLE を使用して、ALTER TABLE が同時操作をブロックしないようにする (ロックを取得しない) こともできます。LOCK=NONE と同等です。

ALTER TABLE に関する MariaDB KB

于 2016-06-18T18:45:50.280 に答える
17

Facebookのオンラインスキーマ変更ツールを参照してください。

http://www.facebook.com/notes/mysql-at-facebook/online-schema-change-for-mysql/430801045932

心の弱い人のためではありません。しかし、それは仕事をします。

于 2011-03-16T03:37:48.640 に答える
7

他のデータベースについて質問されたので、Oracle に関する情報をいくつか示します。

Oracle テーブルへの NULL 列の追加は、データ ディクショナリのみを更新するため、非常に迅速な操作です。これにより、非常に短い期間、テーブルの排他ロックが保持されます。ただし、依存するストアド プロシージャ、ビュー、トリガーなどは無効になります。これらは自動的に再コンパイルされます。

そこから、必要に応じて ONLINE 句を使用してインデックスを作成できます。繰り返しますが、非常に短いデータ ディクショナリ ロックのみです。テーブル全体を読み取り、インデックスを作成するものを探しますが、これを行っている間、誰もブロックしません。

外部キーを追加する必要がある場合は、これを実行して、データが正しいことを Oracle に信頼してもらうことができます。それ以外の場合は、テーブル全体を読み取り、遅くなる可能性のあるすべての値を検証する必要があります (最初にインデックスを作成します)。

デフォルト値または計算値を新しい列のすべての行に配置する必要がある場合は、大規模な更新を実行するか、新しいデータを入力する小さなユーティリティ プログラムを実行する必要があります。特に行が大きくなり、ブロックに収まらなくなった場合、これは遅くなる可能性があります。このプロセス中にロックを管理できます。まだ実行中のアプリケーションの古いバージョンは、この列を認識していないため、こっそりトリガーするか、デフォルトを指定する必要があるかもしれません。

そこから、アプリケーション サーバーで新しいバージョンのコードに切り替えることができ、実行を継続できます。卑劣なトリガーをドロップします。

または、このようなことを行うように設計されたブラック ボックスである DBMS_REDEFINITION を使用できます。

これらすべてをテストするのは非常に面倒なので、メジャー バージョンをリリースするたびに、日曜日の早朝にサービスが停止します。

于 2009-01-21T05:52:58.547 に答える
3

アプリケーションの更新時にデータベースのダウンタイムを許容できない場合は、高可用性のために 2 ノード クラスターを維持することを検討する必要があります。簡単なレプリケーション設定で、あなたが提案するようなほぼ完全にオンラインの構造変更を行うことができます:

  • すべての変更がパッシブ スレーブにレプリケートされるのを待ちます
  • パッシブ スレーブをアクティブ マスターに変更する
  • 旧マスターに構造変更を行う
  • 新しいマスターから古いマスターに変更をレプリケートする
  • マスターのスワッピングを再度行い、新しいアプリのデプロイを同時に行います

必ずしも簡単ではありませんが、通常はダウンタイム 0 で機能します。2 番目のノードはパッシブ ノードである必要はなく、テスト、統計の実行、またはフォールバック ノードとして使用できます。インフラストラクチャがない場合は、1 台のマシン (MySQL の 2 つのインスタンス) 内でレプリケーションをセットアップできます。

于 2010-05-16T03:24:49.350 に答える
2

ぜひ試してみてくださいpt-online-schema-change。このツールを使用して、複数のスレーブを使用して AWS RDS で移行を行っていますが、非常にうまく機能しています。私はあなたに役立つかもしれないそれを行う方法についての詳細なブログ投稿を書きました.

ブログ: http://mrafayaleem.com/2016/02/08/live-mysql-schema-changes-with-percona/

于 2016-10-25T08:44:13.790 に答える
2

一時的な解決...

他の解決策は、新しい列とともに、元のテーブルの主キーを持つ別のテーブルを追加することです。

主キーを新しいテーブルに入力し、新しいテーブルの新しい列に値を入力し、選択操作のためにこのテーブルを結合するようにクエリを変更します。また、この列の値を個別に挿入、更新する必要があります。

ダウンタイムを取得できる場合は、元のテーブルを変更し、DML クエリを変更して、以前に作成した新しいテーブルを削除できます。

それ以外の場合は、percona のクラスタリング方法、レプリケーション、pt-online-schema ツールを使用できます

于 2012-08-13T22:43:37.750 に答える
2

いいえ。MyISAM テーブルを使用している場合、私の理解では、それらはテーブル ロックのみを行います。レコード ロックはなく、シンプルさによってすべてを超高速に保とうとします。(他の MySQL テーブルの動作は異なります。) いずれの場合でも、テーブルを別のテーブルにコピーし、変更してから、それらを切り替えて、違いを更新することができます。

これは非常に大規模な変更であるため、これをサポートする DBMS はないと思います。そもそもテーブルのデータでできるのはメリットと考えられます。

于 2009-01-21T00:25:45.493 に答える
1

次の 2 つの方法のいずれかをお勧めします。

  1. 潜在的な変更を念頭に置いて、データベース テーブルを設計します。たとえば、コンテンツのデータ フィールドを定期的に変更するコンテンツ管理システムを扱ってきました。初期の CMS フィールド要件に合わせて物理データベース構造を構築する代わりに、柔軟な構造を構築する方がはるかに優れています。この場合、blob テキスト フィールド (varchar(max) など) を使用して、柔軟な XML データを保持します。これにより、構造変更の頻度が非常に低くなります。構造の変更にはコストがかかる可能性があるため、ここでもコストをかけるメリットがあります。

  2. システムメンテナンスの時間があります。変更中 (毎月など) にシステムがオフラインになり、1 日のトラフィック量が最も少ない時間帯 (たとえば、午前 3 時から 5 時) に変更がスケジュールされます。変更は実稼働ロールアウトの前にステージングされるため、ダウンタイムの適切な固定ウィンドウ見積もりが得られます。

2a. システムにダウンタイムが発生した場合にサイト全体がダウンしないように、冗長サーバーを用意します。これにより、サイト全体をダウンさせることなく、更新を段階的に「ロールアウト」できます。

オプション 2 と 2a は実行できない場合があります。それらは大規模なサイト/操作のみを対象とする傾向があります。ただし、これらは有効なオプションであり、ここで紹介するすべてのオプションを個人的に使用しました。

于 2009-01-22T20:33:21.937 に答える
1

誰かがまだこれを読んでいる、またはたまたまここに来ている場合、これは mongodb のような NoSQL データベース システムを使用することの大きな利点です。テーブルを変更して、追加機能用の列を追加するか、数百万行と大量の書き込みがある大きなテーブルにインデックスを追加するという同じ問題がありました。非常に長い間ロックされてしまうため、LIVE データベースでこれを行うと、ユーザーがイライラすることになります。小さなテーブルでは、それで逃げることができます。

「テーブルを変更しないように設計する」必要があるという事実が嫌いです。それが今日のウェブサイトの世界ではうまくいかないと思います。人々があなたのソフトウェアをどのように使用するかを予測することはできないため、ユーザーのフィードバックに基づいて急速に変更を加えます。mongodb を使用すると、ダウンタイムなしで自由に「列」を追加できます。実際にそれらを追加することさえありません。新しい列でデータを挿入するだけで、自動的に行われます。

チェックアウトする価値があります: www.mongodb.com

于 2011-07-11T02:03:33.670 に答える
1

この点での Postgres と MySQL の違いは、Postgres ではテーブルを再作成せず、Oracle と同様にデータ ディクショナリを変更することです。したがって、操作は高速ですが、他の人が上で述べたように、非常に短い時間だけ排他的 DDL テーブル ロックを割り当てる必要があります。

MySQL では、操作はトランザクションをブロックしながらデータを新しいテーブルにコピーします。これは、v. 5.6 より前の MySQL DBA にとって主な苦痛でした。

良いニュースは、MySQL 5.6 のリリース以降、制限がほぼ解除され、MYSQL DB の真の力を享受できるようになったことです。

于 2015-01-29T21:38:10.163 に答える
1

一般的に、答えは「いいえ」になります。多くの更新が必要になる可能性のあるテーブルの構造を変更しています」と私はそれに完全に同意します。これを頻繁に行うことが予想される場合は、「ダミー」列VIEWの代わりに s を使用します。データ用のテーブルのSELECT. IIRC, ビューの定義を変更することは比較的軽量であり、クエリプランがコンパイルされるときにビューを介した間接化が行われます. 費用は、列を新しいテーブルに追加して作成する必要があることです.JOINコラムで見る。

もちろん、これは外部キーを使用して削除のカスケードなどを実行できる場合にのみ機能します。もう 1 つの利点は、データの組み合わせを含む新しいテーブルを作成し、クライアントの使用を妨げずにビューをそのテーブルに向けることができることです。

ちょっとした考え。

于 2009-01-22T20:25:19.550 に答える
1

SeanDowney が言及pt-online-schema-changeしたように、ここの質問で説明したことを行うための最良のツールの 1 つです。私は最近、ライブ DB で多くのスキーマ変更を行いましたが、かなりうまくいきました。詳細については、私のブログ投稿http://mrafayaleem.com/2016/02/08/live-mysql-schema-changes-with-percona/を参照してください。

于 2016-02-08T10:49:35.150 に答える
0

ダミー列は、型を予測できる (そして null 可能にできる) 場合に適しています。ストレージ エンジンが null を処理する方法を確認してください。

MyISAM は、通過中、電話、空港でテーブル名を口にするだけでもすべてをロックします。それはちょうどそれをします...

そうは言っても、ロックはそれほど大したことではありません。新しい列のデフォルト値をすべての行に追加しようとしているのではなく、null のままにしておく限り、ストレージ エンジンがそれを書き込もうとしないほどスマートである限り、メタデータを更新するのに十分な時間保持されます。もしあなたが新しい値を書こうとするなら、まあ、あなたは乾杯です.

于 2009-01-21T05:05:28.003 に答える
0

TokuDB は列を追加/ドロップし、インデックスを「ホット」に追加できます。テーブルはプロセス全体で完全に利用可能です。www.tokutek.comから入手できます

于 2011-11-28T02:20:07.657 に答える
-7

あまり。

結局のところ、テーブルの基礎となる構造を変更しているのです。これは、基礎となるシステムにとって非常に重要な情報です。また、(おそらく) ディスク上で多くのデータを移動しています。

これを頻繁に行う予定がある場合は、将来の使用に備えて「ダミー」列をテーブルに埋め込むだけの方がよいでしょう。

于 2009-01-21T00:26:46.397 に答える