MySQL 5.1 リファレンスマニュアル :: 1 一般情報 :: 1.8 MySQLの標準への準拠 :: 1.8.5 MySQLと標準SQLとの違い :: 1.8.5.3 トランザクションとアトミックオペレーション
« 1.8.5.2 SELECT INTO TABLE

1.8.5.4 ストアドプロシージャとトリガ »
Section Navigation      [Toggle]
  • 1.8.5 MySQLと標準SQLとの違い
  • 1.8.5.1 サブクエリのサポート
  • 1.8.5.2 SELECT INTO TABLE
  • 1.8.5.3 トランザクションとアトミックオペレーション
  • 1.8.5.4 ストアドプロシージャとトリガ
  • 1.8.5.5 外部キー
  • 1.8.5.6 ビュー
  • 1.8.5.7 コメントの開始記号としての'--'

1.8.5.3. トランザクションとアトミックオペレーション

MySQL サーバ(バージョン 3.23-max およびすべてのバージョン 4.0 以降)では、InnoDBトランザクションストレージエンジンでトランザクションがサポートされています。InnoDBは完全に ACIDに準拠しています。詳しくは 章 13. ストレージエンジンとテーブルタイプ を参照してください。トランザクションエラーの取り扱いにおける、標準SQLとInnoDBとの違いについては項13.5.15. 「InnoDB エラー処理」を参照してください。

MySQL サーバのその他の非トランザクションストレージエンジン(MyISAM など)は、「アトミックオペレーション」と呼ばれる別のデータ整合性のパラダイムに従います。トランザクションの観点では、MyISAM テーブルは事実上、常に AUTOCOMMIT=1モードで動作すると言えます。アトミックオペレーションでは多くの場合、パフォーマンスの高さに値する整合性が確保されます。

両方のパラダイムをサポートする MySQL サーバでは、ユーザはアトミックオペレーションの速度を必要とするか、アプリケーションでトランザクション機能を使用する必要があるかを選択することができます。この選択は、テーブルごとに行うことができます。

ほとんどの場合、トランザクションストレージエンジンと非トランザクションストレージエンジンのどちらを選ぶかの決め手となるのはパフォーマンスです。トランザクションテーブルの場合、はるかに大きなメモリとディスク領域が必要で、CPU のオーバーヘッドも大きくなります。しかし、InnoDBのようなトランザクションストレージエンジンには特有の機能も多数あります。MySQLサーバのモジュール設計によって、このようなさまざまなストレージエンジンすべてを同時に使用することができるので、さまざまな要件に合わせて、あらゆる条件で最適なパフォーマンスを確保することが可能です。

しかし、MySQL サーバの機能を使用して、非トランザクションの MyISAM テーブルでも厳密な整合性を確保するにはどのようにすればよいのでしょうか。また、非トランザクションテーブルの機能はトランザクションストレージエンジンにどのように対抗できるのでしょうか。

  • トランザクションパラダイムでは、重大な状況で COMMITではなく ROLLBACK の呼び出しに依存するようにアプリケーションが作成されている場合、トランザクションの方が便利です。また、トランザクションでは、完了していない更新や失敗した活動がデータベースにコミットされることはない。サーバには自動ロールバックを行う機会が与えられ、データベースは保護されます。

    非トランザクションテーブルを使用している場合、MySQL サーバでは、ほとんどの場合、更新前に簡単なチェックを組み込んだり、データベースの不整合をチェックして、不整合が発生した場合には自動的に修復または警告する簡単なスクリプトを実行したりすることで、発生する可能性がある問題を解決することができます。MySQL ログを使用したり、別のログを 1 つ追加したりするだけで、通常、データの整合性が失われることなく、完全にテーブルを修復することができます。

  • ほとんどの場合、重要なトランザクション更新はアトミックな更新に記述し直すことができます。通常、トランザクションによって解決される整合性の問題はすべて、LOCK TABLES またはアトミックな更新を使用して解決することができます。これによって、サーバが自動的に停止するという、トランザクションデータベースシステムと共通する問題が回避されます。

  • MySQL サーバを安全に使用するには、トランザクションテーブルを使用するかどうかに関係なく、バックアップを作成し、バイナリログをオンにするだけです。これにより、他のトランザクションデータベースシステムで可能なように、どのような状況からもリカバリすることができます。使用するデータベースシステムに関係なく、どのような場合でもバックアップを作成することが望ましいのは当然です。

トランザクションパラダイムには長所と短所があります。多数のユーザおよびアプリケーション開発者は、停止が発生する、または停止が必要な問題に関するコード化の容易さに頼っています。しかし、アトミックオペレーションのパラダイムに慣れていなかったり、トランザクションの方が詳しいという場合でも、非トランザクションテーブルの速度が、最も高速で最適に調整されたトランザクションテーブルの速度の 3 倍から 5 倍も速いという長所を考えてみてください。

整合性が最も重要な状況では、MySQL サーバは、非トランザクションテーブルでもトランザクションレベルの信頼性と整合性を提供します。LOCK TABLESを使用してテーブルをロックすると、整合性チェックが行われるまで、すべての更新が延期されます。テーブルエンドで同時挿入が可能なREAD LOCALロック(書き込みロックの逆)が設定されている場合、他のクライアントによる読み取りと挿入は引き続き行うことができます。新しく挿入したレコードは、読み取りがロックされているクライアントには、読み取りロックが解除されるまで表示されません。INSERT DELAYEDを使用すると、ロックが解除されるまで挿入をローカルキューに入れることができ、クライアントは挿入が完了するまで待機する必要はありません。項6.3.3. 「同時挿入」 および 項12.2.4.2. 「INSERT DELAYED 構文」 を参照してください。

ここでいう「アトミック」とは、魔法のようなものではありません。個々の更新の実行中は、他のユーザがそれを妨害できないようにするとともに、自動ロールバック(あまり注意を払わなかった場合に、トランザクションテーブルで行われることがあります)が行われないようにすることができるというだけです。また、MySQL サーバでは、ダーティリードが行われることもありません。

非トランザクションテーブルを使用する際のテクニックは、以下のとおりです。

  • LOCK TABLESを使用して、通常はトランザクションを必要とするループをコード化することができる。そのため、実行中にレコードを更新するカーソルが不要です。

  • ROLLBACKを使用しないように、以下の方法を使用することができます。

    1. LOCK TABLES を使用して、アクセスするすべてのテーブルをロックします。

    2. 更新する前に条件をテストします。

    3. すべてに問題がなければ、更新します。

    4. 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_owed_to_us=money_owed_to_us-125
      WHERE
        customer_id=id AND address='old address' AND phone='old phone';
    

    これは非常に効率的で、別のクライアントがpay_backまたは money_owed_to_us カラムの値を変更していても動作します。

  • 多くの場合、ユーザは、複数のテーブルの一意の識別子を管理するために LOCK TABLES や ROLLBACKを使用していました。これは、AUTO_INCREMENTカラムおよびSQL関数LAST_INSERT_ID()またはC API関数mysql_insert_id()を使用することで、ロックやロールバックをせずにはるかに効率的に処理することができます。項11.10.3. 「情報関数」 および 項23.2.3.37. 「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;
    
Copyright © 1997, 2010, Oracle and/or its affiliates. All rights reserved. Legal Notices
Top / Previous / Next / Up / Table of Contents
© 2010, Oracle Corporation and/or its affiliates