ライブ本番データベースのテーブルを変更する


24

ほとんどの「人気のある」(MySQL、Postgres ...)データベースシステムは、稼働中の本番データベース上のテーブルの変更(列のタイプの追加、削除、変更など)をどのように処理しますか?

私が知って正しい方法は、バックアップのすべてのスケジュールのダウンタイムにあり、その後、変更を行うのですか。

しかし... ...現在のデータベースシステムは、これらのことを何も停止することなく「オンライン」で行うことをサポートしていますか (変更または削除されたばかりの列を参照するクエリを遅らせるだけの場合があります)

そしてALTER TABLE...、ライブ実行中のデータベースで実行するとどうなりますか?これが発生すると、すべてが停止しますか?データが破損することはありますか?等

繰り返しますが、これらは私が遭遇するものであるため、私は主にPostgresまたはMySQLに言及しています。

(そして、はい、「正しい方法」を行う前にこれをしなければならなかったときはいつでも、物事をバックアップし、ダウンタインをスケジュールします。ダーティ」または「クイック、ライブ、ダーティ」スキーマ変更を実際にサポートしているDBシステムがある場合)


誰かがFacebookスクリプトからMySQLのオンラインスキーマ変更を提案しましたここにチュートリアルとソースがあります)...それを行うための「ハッキング」方法のセットを自動化する良い方法のようです...誰もがそれを使用したことがあります生産に似た何か?


3
注:特定された「正しい方法」は、PostgreSQLではなくMySQLに関連しています。PostgreSQLの「正しい方法」は通常、非常に簡単ですが、関与することもあります。を使用するpg_reorgと、より困難なシナリオに役立ちます。
ショーン

できる限り多くの戦略を説明してくれる人と一緒に、これに関する詳細なビデオを作成したいと思っていました。
サンディーパンナス

回答:


22

ALTER TABLEPostgreSQL ACCESS EXCLUSIVESELECTを発行すると、を含むすべてをブロックするロックがかかります。ただし、テーブルが書き換えを必要としない場合、新しいロックが不要な場合UNIQUECHECKまたはFOREIGN KEY検証のために高価なフルテーブルスキャンが必要な場合など、このロックは非常に短い場合があります。

疑わしい場合は、一般的に試してみてください!PostgreSQLのすべてのDDLはトランザクション型であるため、ALTER TABLE時間がかかりすぎて他のクエリを保留し始めた場合にキャンセルしても問題ありません。さまざまなコマンドで必要なロックレベルは、ロックページに記載されています

一部の通常低速の操作は、ダウンタイムなしで安全に実行できるように高速化できます。たとえば、テーブルがtあり、顧客がすべての顧客コードをで始める必要があると顧客が決定customercode integer NOT NULLしたtextために列を変更するX場合、次のように記述できます。

ALTER TABLE t ALTER COLUMN customercode TYPE text USING ( 'X'||customercode::text );

...しかし、それは再書き込みのためにテーブル全体をロックします。で列を追加する場合も同様DEFAULTです。長いロックを回避するためにいくつかの手順で実行できますが、アプリケーションは一時的な複製に対処できる必要があります。

ALTER TABLE t ADD COLUMN customercode_new text;
BEGIN;
LOCK TABLE t IN EXCLUSIVE MODE;
UPDATE t SET customercode_new = 'X'||customercode::text;
ALTER TABLE t DROP COLUMN customercode;
ALTER TABLE t RENAME COLUMN customercode_new TO customercode;
COMMIT;

これにより、プロセス中の書き込みのみが防止さtれます。ロック名EXCLUSIVEは、それ以外のSELECTすべて除外するという点でやや欺de的です。ACCESS EXCLUSIVEモードは、すべてを完全に除外する唯一のモードです。ロックモードを参照してください。が必要とするロックのアップグレードが原因で、この操作がデッドロックロールバックする可能性があるというリスクがありますALTER TABLEが、最悪の場合は再度実行する必要があります。

そのロックを回避しtINSERTまたはUPDATEが入るたびにcustomercode_newから自動的に生成されるトリガー関数を作成することで、すべてをライブで実行することもできcustomercodeます。

また、そこのようなツールが内蔵されているCREATE INDEX CONCURRENTLYALTER TABLE ... ADD table_constraint_using_indexthat'reは、DBAは、並行性に優しい方法で、もっとゆっくり仕事をしていることにより、排他的ロック期間を短縮することができるように設計されています。

pg_reorgツールまたはその後継pg_repackにもいくつかのテーブル再構築操作に使用することができます。


1
@Craigが言ったことで重要だったのは、「書き直す必要がない場合」でした。ALTER TABLE t ADD COLUMN i INTロックを取得すると、anの使用は高速操作(通常<1ms)です。ただし、ロックを取得すると接続がキューイングされる可能性があるため、「無料」ではありません... MySQLで行うよりも世界の方が優れています。NOT NULL制約を追加することはより難しく、心臓の偽装のためではありません。
ショーン

それがpg_repack後継者の改良されたコンセンサスのようですpg_reorg
アーウィンブランドステッター

良い答えは、デフォルトの(または計算された)列を追加する「ブロック」の少ない方法に関して、新しいテーブル全体を作成し、古いテーブルをブロックして挿入/更新/削除することです。最後に、選択のために古いテーブルで簡単な排他ロックを発行し、削除して、新しい名前を古い名前に変更します。あなたのシナリオに応じてあなたも古いと問題に挿入をブロックすることなく、新規を移入するために始めることができる排他ロックだけでしばらく(うまくいけば、単にいくつかの新しいレコードを挿入)差分を解く
ジャン・

7

Perconaは、オンラインスキーマ変更を実行するための独自のツールを考案しました。

このツールはpt-online-schema-changeと呼ばれます

トリガーが関係するため、ドキュメントを注意深くお読みください。

ドキュメントによると、行われる主な操作は

  • 健全性チェック
  • チャンキング
  • オンラインスキーマ変更
    • 一時テーブルを作成および変更する
    • テーブルから一時テーブルへの変更をキャプチャする
    • テーブルから一時テーブルに行をコピーします
    • テーブルと一時テーブルを同期する
    • テーブルと一時テーブルの交換/名前変更
    • 掃除

おかげで、Facebookのアプローチの「洗練された」バージョンのように思えるので、もっと信頼できます
...-NeuronQ

独自のMySQLサーバーを実行している場合、pt-online-schema-changeを使用することをお勧めします。Percona Tools 2.2の時点で、(残念ながら)AWS上のRDS / Auroraをサポートしていません。pt-online-schema-changeは、ソーステーブルにトリガーを挿入して、行(MyISAMの優先度が低い)を宛先table_tempにコピーし、ソースと宛先の間ですべての行が同期している場合、最後に単一のクイックロックドロップと名前変更を行いますテーブル。
phpguru

6

システムをシャットダウンして、すべての変更を一度に行うことは非常に危険です。何かがうまくいかず、頻繁にそれが起こった場合、簡単に戻る方法はありません。

アジャイル開発者として、テーブルが修正され、読み取られるため、ダウンタイムなしでテーブルをリファクタリングする必要がある場合があります。

次のアプローチでは、変更がロールバックが非常に簡単ないくつかの低リスクの手順で行われるため、リスクが低くなります。

  • テーブルにアクセスするすべてのモジュールが自動テストで十分にカバーされていることを確認してください。
  • 新しいテーブルを作成します。古いテーブルと新しいテーブルの両方を変更するように、古いテーブルを変更するすべてのプロシージャを変更します。
  • 既存のデータを新しい構造に移行します。サーバーの全体的なパフォーマンスに深刻な影響を与えないように、小さなバッチで実行してください。
  • データの移行が成功したことを確認します。
  • 選択手順の一部を古いテーブルから新しいテーブルにリダイレクトします。自動化されたテストを使用して、変更されたモジュールがまだ正しいことを確認します。それらのパフォーマンスが許容できることを確認してください。変更したプロシージャを展開します。
  • すべてのレポートが新しいテーブルを使用するまで、前の手順を繰り返します。
  • 新しいテーブルにのみアクセスするように、テーブルを変更するプロシージャを変更します。
  • 古いテーブルをアーカイブし、システムから削除します。

このアプローチを何度も使用して、大規模な運用中のテーブルを、ダウンタイムなしで問題なく変更しました。


3
素晴らしい...しかし、それはまさに私が避けたい「痛み」のタイプです:)
NeuronQ

@NeuronQ「戻る簡単な方法はありません」-Postgresにあります:トランザクションにすべてを入れrollback、何かがうまくいかない場合。
a_horse_with_no_name

2

はい、多くの最新のデータベースでは、列を追加したり、列の特性を変更したりできます(null可能の追加や削除など)。

列をドロップすると、データは失われますが、破損の恐れはあまりありません。



-1

ALTER TABLEステートメントで何が起こるかについての質問に対処するために、それはあなたの変更の程度に依存します。特定の場合、少なくともMS SQL Serverで新しい列を追加すると、エンジンはテーブルの一時コピーを作成しますが、新しいテーブル定義を作成し、そこにデータを挿入します。したがって、変更の期間中、ユーザーはテーブルにアクセスできません。

MSSQLサーバーの特定の操作の例はこちらです:http : //support.microsoft.com/kb/956176/en-us

他のRMDBにも同様のメソッドがあると思いますが、正確な実装はベンダーのドキュメントで確認する必要があります。


-1これはSQL Serverにとって完全に間違っています。「少なくともMS SQL Serverで新しい列を追加すると、エンジンは新しいテーブル定義を作成し、データを挿入して、テーブルの一時コピーを作成します。 「そこにある
AK

@AlexKuznetsov-私は前の行を考えました、そしてリストされたいくつかのケースとのリンクはこれが常に起こるとは限らないことを明確にするでしょう。これをよりよく反映するように文を修正しました。
-SchmitzIT

1
SQL Server自体の動作ではなく、GUI、SSMSの動作に言及しています。リンクに従って、T-SQLを直接使用してDDLを変更することをお勧めします。SSMSは、DDLを変更するための非常に優れたツールではありません。
AK

@AlexKuznetsov-私は、落胆としてではなく、リスクがあると言っているとして記事を読みました。とにかく、私はGUIビットの記事をリンクしませんでしたが、基になるデータ構造の変更により一時テーブルの作成につながるALTERステートメントにつながる操作のいくつかの指標として。T-SQLから直接ステートメントを発行するときにまったく同じことが当てはまるかどうかはテストしていませんが、プロセスはかなり似ており、SLサーバーが舞台裏で脚注を行うと思います。
-SchmitzIT

プロファイラーを起動し、ALTER TABLEステートメントを直接実行して、何が起こっているのかを確認できます。次に、ダイアログボックスを使用してテーブルを変更し、実行されているコマンドを自分で確認できます。
AK
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.