MySQL サーバ(バージョン 3.23-max
およびすべてのバージョン 4.0
以降)では、InnoDB
および
BDB
トランザクションストレージエンジン
でトランザクションがサポートされています。InnoDB
は、完全に ACID
に準拠しています。 See
章 7. MySQL のテーブル型。
MySQL
サーバのその他の非トランザクションテーブル型(MyISAM
など)は、``アトミックオペレーション
''と呼ばれる別のデータ整合性のパラダイムに従います。トランザクションの観点では、MyISAM
テーブルは事実上、常に
AUTOCOMMIT=1
モードで動作すると言えます。アトミックオペレーションでは多くの場合、パフォーマンスの高さに値する整合性が確保されます。
両方のパラダイムをサポートする MySQL サーバでは、ユーザはアトミックオペレーションの速度を必要とするか、アプリケーションでトランザクション機能を使用する必要があるかを選択することができます。この選択は、テーブルごとに行うことができます。
ほとんどの場合、トランザクションテーブル型と非トランザクションテーブル型のどちらを選ぶかの決め手となるのはパフォーマンスです。トランザクションテーブルの場合、はるかに大きなメモリとディスク領域が必要で、CPU
のオーバーヘッドも大きくなります。しかし、InnoDB
のようなトランザクションテーブル型には特有の機能も多数あります。MySQL
サーバのモジュール設計によって、このようなさまざまなストレージエンジンすべてを同時に使用することができるので、さまざまな要件に合わせて、あらゆる条件で最適なパフォーマンスを確保することが可能です。
しかし、MySQL
サーバの機能を使用して、非トランザクションの
MyISAM
テーブルでも厳密な整合性を確保するにはどのようにすればよいのでしょうか。また、非トランザクションテーブルの機能はトランザクションテーブル型にどのように対抗できるのでしょうか。
トランザクションパラダイムでは、重大な状況で
COMMIT
ではなく
ROLLBACK
の呼び出しに依存するようにアプリケーションが作成されている場合、トランザクションの方が便利である。また、トランザクションでは、完了していない更新や失敗した活動がデータベースにコミットされることはない。サーバには自動ロールバックを行う機会が与えられ、データベースは保護される。
MySQL サーバでは、ほとんどの場合、更新前に簡単なチェックを組み込んだり、データベースの不整合をチェックして、不整合が発生した場合には自動的に修復または警告する簡単なスクリプトを実行したりすることで、発生する可能性がある問題を解決することができる。MySQL ログを使用したり、別のログを 1 つ追加したりするだけで、通常、データの整合性が失われることなく、完全にテーブルを修復することができる。
ほとんどの場合、重要なトランザクション更新はアトミックな更新に記述し直すことができる。通常、トランザクションによって解決される整合性の問題はすべて、LOCK
TABLES
またはアトミックな更新を使用して解決することができる。これによって、サーバが自動的に停止するという、トランザクションデータベースシステムと共通する問題が回避される。
サーバが停止すると、トランザクションシステムでもデータが失われる可能性がある。個々のシステムの違いは、データが失われる可能性がある時間がどれだけ短いかという点だけである。100% 安全なシステムはなく、``十分に安全'' なだけである。最も安全なトランザクションデータベースシステムと言われている Oracle でさえも、そのような状況ではデータが失われることがあると報告されている。
MySQL サーバを安全に使用するには、トランザクションテーブルを使用するかどうかに関係なく、バックアップを作成し、バイナリログをオンにすればよいだけである。これにより、他のトランザクションデータベースシステムで可能なように、どのような状況からもリカバリすることができる。使用するデータベースシステムに関係なく、どのような場合でもバックアップを作成することが望ましいのは当然である。
トランザクションパラダイムには長所と短所があります。多数のユーザおよびアプリケーション開発者は、停止が発生する、または停止が必要な問題に関するコード化の容易さに頼っています。しかし、アトミックオペレーションのパラダイムに慣れていなかったり、トランザクションの方が詳しいという場合でも、非トランザクションテーブルの速度が、最も高速で最適に調整されたトランザクションテーブルの速度の 3 倍から 5 倍も速いという長所を考えてみてください。
整合性が最も重要な状況では、MySQL
サーバは、非トランザクションテーブルでもトランザクションレベルの信頼性と整合性を提供します。LOCK
TABLES
を使用してテーブルをロックすると、整合性チェックが行われるまで、すべての更新が延期されます。読み取りロック(書き込みロックの逆)のみが設定されている場合、読み取りと挿入は引き続き行うことができます。新しく挿入したレコードは、読み取りがロックされているクライアントには、読み取りロックが解除されるまで表示されません。INSERT
DELAYED
を使用すると、ロックが解除されるまで挿入をローカルキューに入れることができ、クライアントは挿入が完了するまで待機する必要はありません。
See 項6.4.3.2. 「INSERT DELAYED
構文」。
ここでいう ``アトミック'' とは、魔法のようなものではありません。個々の更新の実行中は、他のユーザがそれを妨害できないようにするとともに、自動ロールバック(あまり注意を払わなかった場合に、トランザクションテーブルで行われることがあります)が行われないようにすることができるというだけです。また、MySQL サーバでは、ダーティリードが行われることもありません。
非トランザクションテーブルを使用する際のテクニックは、以下のとおりです。
LOCK TABLES
を使用して、通常はトランザクションを必要とするループをコード化することができる。そのため、実行中にレコードを更新するカーソルが不要である。
ROLLBACK
を使用しないように、以下の方法を使用することができる。
LOCK TABLES ...
を使用して、アクセスするすべてのテーブルをロックする。
条件をテストする。
すべてに問題がなければ、更新する。
UNLOCK TABLES
を使用して、ロックを解除する。
これは通常、ロールバックが行われる可能性があるトランザクションを使用するよりも、はるかに速い方法である。ただし、更新の途中でスレッドが停止された場合は、この方法では対応することができない。その場合、すべてのロックが解除されるが、一部の更新が実行されていない可能性がある。
関数を使用して、1 回の操作でレコードを更新することもできる。次のようなテクニックを使用すると、非常に効率的なアプリケーションを取得することができる。
現在の値に関連してフィールドを変更する。
実際に変更されたフィールドのみを更新する。
たとえば、顧客情報に対して更新を行う場合、変更された顧客データのみを更新し、変更されたデータ、または変更されたデータに依存するデータが元のレコードと比較して変更されていないことだけをテストする。変更されたデータのテストは、UPDATE
ステートメントで WHERE
節を使用して行われる。レコードが更新されなかった場合、''Some
of the data you have changed has been changed by another
user.''
というメッセージがクライアントに表示される。その場合、ウィンドウに元のレコードと新しいレコードを表示して、使用する必要がある顧客レコードのバージョンをユーザが決定できるようにする。
これによって、カラムロックと類似しているが、現在の値に関連する値を使用して、カラムの一部のみが更新される点で、実際はカラムロックよりすぐれた機能が実現する。つまり、一般的な
UPDATE
ステートメントは次のようになる。
UPDATE tablename SET pay_back=pay_back+125; UPDATE customer SET customer_date='current_date', address='new address', phone='new phone', money_he_owes_us=money_he_owes_us-125 WHERE customer_id=id AND address='old address' AND phone='old phone';
これは非常に効率的で、別のクライアントが
pay_back
または
money_he_owes_us
カラムの値を変更していても動作する。
多くの場合、ユーザは、複数のテーブルの一意の識別子を管理するために
ROLLBACK
や LOCK
TABLES
を使用していた。これは、AUTO_INCREMENT
カラムおよび SQL 関数
LAST_INSERT_ID()
または C API 関数
mysql_insert_id()
を使用することで、はるかに効率的に処理することができる。
See 項11.1.3.32. 「mysql_insert_id()
」。
通常、行レベルのロックをコード化することができる。状況によっては実際にこれが必要なので、InnoDB
テーブルでは行レベルのロックがサポートされている。MyISAM
では、テーブルでフラグカラムを使用し、以下のようなことを実行することができる。
UPDATE tbl_name SET row_flag=1 WHERE id=ID;
レコードが見つかり、元のレコードで
row_flag
がすでに 1
でなくなっていた場合、MySQL
は、影響を受けたレコードの数として 1
を返す。
MySQL サーバでは前述のクエリが次のように変更されると考えることができる。
UPDATE tbl_name SET row_flag=1 WHERE id=ID AND row_flag <> 1;
This is a translation of the MySQL Reference Manual that can be found at dev.mysql.com. The original Reference Manual is in English, and this translation is not necessarily as up to date as the English version.