MySQL Server (バージョン 3.23-max およびすべてのバージョン 4.0 以降) では、InnoDB
トランザクションストレージエンジンでトランザクションがサポートされています。MySQL 5.5 以上では、セクション14.1.1「デフォルトの MySQL ストレージエンジンとしての InnoDB」で説明しているように、新しく作成したテーブルではデフォルトで InnoDB
が使用されます。デフォルトで、InnoDB
は完全な ACID コンプライアンスを提供します。ACID コンプライアンスと raw パフォーマンスとのバランスを取るように設定を調整する方法については、セクション14.2.1「MySQL および ACID モデル」を参照してください。トランザクションエラーの取り扱いにおける、標準 SQL と InnoDB
との違いについては、セクション14.19.4「InnoDB のエラー処理」を参照してください。
MySQL Server での非トランザクションストレージエンジン (MyISAM
など) は、「アトミック操作」と呼ばれるデータ整合性に関する別のパラダイムに従います。MyISAM
テーブルは実質上常に、autocommit = 1
モードで操作します。変更されたデータは、一度に 1 つのステートメントでディスクに書き込まれるため、一連の関連する DML 操作は途中で妨害される可能性があり、この操作の一貫性を保証することが非常に困難になります。したがって、このモードは読み取りが大半のワークロードに適しています。トランザクションの条件では、それぞれの特定の更新が実行している間、ほかのユーザーがこれを妨げることができず、自動的なロールバックが存在できず、ダーティー読み取りが存在しません。ただし、これらの特性は単一の操作に適用され、一つの単位として成功または失敗する関連した更新には適用されません。LOCK TABLES
ステートメントなどの回避策は、非トランザクションテーブルへの並列書き込みアクセスを制限します。
同じアプリケーション内の別々のテーブルの場合でも、どちらのパラダイムを使用するかを選択できます。信頼性と高いパフォーマンスを両立させる場合にはトランザクション機能を、(たとえばレプリケーションスレーブサーバーでの) 重要でない読み取りが大半のデータにはアトミック操作を選択できます。
InnoDB
などのトランザクションストレージエンジンでは、負荷のかかる読み取り/書き込みワークロードに対する高い信頼性をサポートする多くの重要な機能が用意されています。結果として、トランザクションテーブルのメモリーおよびディスク容量の要件は高くなり、CPU オーバーヘッドが大きくなります。MySQL Server のモジュラー設計によって、さまざまなストレージエンジンの並列使用が可能になり、さまざまな要件に適合し、あらゆる状況で最適なパフォーマンスを実現できます。
非トランザクションテーブルでの信頼性に対する回避策
しかし、非トランザクションの MyISAM
テーブルとの完全性も維持するには、MySQL Server の機能をどのように使用すればよいでしょうか。また、このような機能はトランザクションストレージエンジンにどのように匹敵するでしょうか。
-
重大な状況で
COMMIT
ではなくROLLBACK
の呼び出しに依存するようにアプリケーションが作成されている場合、トランザクションの方が便利です。トランザクションでは、完了していない更新や失敗したアクティビティーがデータベースにコミットされていないことも確認します。サーバーには、自動ロールバックを行う機会が与えられ、データベースは保存されます。非トランザクションテーブルを使用する場合は、更新の前にチェックを含めることや、不整合についてデータベースをチェックし、このような不整合が発生した場合には自動的に修復または警告するスクリプトを実行することによって、アプリケーションレベルで潜在的な問題を解決する必要があります。MySQL ログを使用するか、さらに 1 つのログを追加することになっても、データの完全性を損なわずに、通常どおりテーブルを修正できます。
場合によっては、重要なトランザクション更新は、アトミックになるように書き換えることができます。
LOCK TABLES
またはアトミック更新で複数の DML 操作を行うことができ、並列書き込みアクセスを制限することによってデッドロックが起こらないようにします。テーブルの末尾での並列挿入を可能にする、テーブルに対するREAD LOCAL
ロック (書き込みロックの反対) を取得した場合、読み取りは許可され、ほかのクライアントによる挿入も許可されます。新しく挿入したレコードは、読み取りがロックされているクライアントには、読み取りロックが解除されるまで表示されません。INSERT DELAYED
を使用すると、ロックが解除されるまで挿入をローカルキューに入れることができ、クライアントは挿入が完了するまで待機する必要はありません。セクション8.10.3「同時挿入」およびセクション13.2.5.2「INSERT DELAYED 構文」を参照してください。MySQL Server で安全性を確保するには、使用するテーブルの種類に関係なく、定期的にバックアップを作成してバイナリロギングをオンにします。使用するデータベースシステムに関係なく、どのような場合でもバックアップを作成することは賢明です。
次に、非トランザクションテーブルを操作するための手法を示します。
LOCK TABLES
を使用して、通常はトランザクションを必要とするループをコード化することができ、実行中にレコードを更新するカーソルが不要です。-
ROLLBACK
を使用しないようにするため、次の方法を使用することができます。LOCK TABLES
を使用して、アクセスするすべてのテーブルをロックします。更新を実行する前に、true になっている必要がある条件をテストします。
条件が満たされていれば、更新します。
UNLOCK TABLES
を使用して、ロックを解除します。
注記この解決方法は、だれかが更新の途中でスレッドを強制終了したときの状況に対処しません。その場合、すべてのロックが解除されますが、一部の更新が実行されていない可能性があります。
-
次の手法を使用して、関数を用いて単一の操作でレコードを更新することもできます。
現在の値に関連してカラムを変更します。これにより、別のクライアントがその間にカラム値を変更した場合でも、更新は正しくなります。
実際に変更されたカラムのみを更新します。これが一般的にデータベースにとって適切な方法になります。
-
一意の識別子を管理するときに、
AUTO_INCREMENT
カラムと、LAST_INSERT_ID()
SQL 関数またはmysql_insert_id()
C API 関数のどちらかを使用することによって、LOCK TABLES
やROLLBACK
などのステートメントを回避できます。セクション12.14「情報関数」およびセクション23.7.7.37「mysql_insert_id()」を参照してください。行レベルロックが必要な状況では、
InnoDB
テーブルを使用します。それ以外の場合、MyISAM
テーブルでは、テーブルでフラグカラムを使用して、次のような操作を実行することができます。UPDATE tbl_name SET row_flag=1 WHERE id=ID;
レコードが見つかり、元の行で
row_flag
がすでに1
でなくなっていた場合、MySQL は、影響を受けた行の数として1
を返します。MySQL Server が前述のステートメントを次のように変更したと考えることができます。UPDATE tbl_name SET row_flag=1 WHERE id=ID AND row_flag <> 1;