MySQL 8.0 リファレンスマニュアル


MySQL 8.0 リファレンスマニュアル  /  ...  /  NDB Cluster でのトランザクション処理に関する制限

23.1.7.3 NDB Cluster でのトランザクション処理に関する制限

NDB Cluster には、トランザクションの処理に関していくつかの制限があります。 これらには、次のものが含まれます。

  • トランザクション分離レベル.  NDBCLUSTER ストレージエンジンは READ COMMITTED トランザクション分離レベルのみをサポートします。 (たとえば、InnoDBREAD COMMITTEDREAD UNCOMMITTEDREPEATABLE READ、および SERIALIZABLE をサポートします。) NDBREAD COMMITTED を行単位で実装する必要があることに注意してください。読取りリクエストが行を格納しているデータノードに到着すると、その時点で最後にコミットされたバージョンの行が返されます。

    コミットされていないデータが返されることはありませんが、複数の行を変更するトランザクションが同じ行を読み取るトランザクションと同時にコミットする場合、特定の行読取りリクエストを他のトランザクションのコミットの前または後に処理できるため、読取りを実行するトランザクションは、これらの間で異なる行に対して値の前、値の後、またはその両方を監視できます。

    特定のトランザクションが変更前または変更後の値のみを読み取るようにするには、SELECT ... LOCK IN SHARE MODE を使用して行ロックを設定します。 このような場合、ロックは、所有しているトランザクションがコミットされるまで保持されます。 行ロックを使用すると、次の問題が発生することもあります:

    • ロック待機タイムアウトエラーの頻度の向上と同時実行性の低下

    • コミットフェーズを必要とする読取りによるトランザクション処理オーバーヘッドの増加

    • 使用可能な同時ロック数を使い果たす可能性があり、MaxNoOfConcurrentOperations によって制限されています

    NDB では、LOCK IN SHARE MODEFOR UPDATE などの修飾子を使用しないかぎり、すべての読取りに READ COMMITTED が使用されます。 LOCK IN SHARE MODE では共有行ロックが使用され、FOR UPDATE では排他行ロックが使用されます。 一意キー読取りでは、自己一貫性読取りを保証するために NDB によってロックが自動的にアップグレードされます。BLOB 読取りでは、一貫性のために追加ロックも使用されます。

    NDB のトランザクション分離レベルのクラスタ実装が NDB データベースのバックアップおよび復元に与える影響については、セクション23.5.8.4「NDB Cluster バックアップのトラブルシューティング」 を参照してください。

  • トランザクションと BLOB または TEXT カラム.  NDBCLUSTER は、MySQL から認識できるテーブルに MySQL の BLOB または TEXT データ型のいずれかを使用するカラム値の一部のみを格納します。BLOB または TEXT の残りの部分は、MySQL からアクセスできない別の内部テーブルに格納されます。 これに関連して、これらの型のカラムを含むテーブルに対して SELECT ステートメントを実行するときに常に注意すべき問題が 2 つ発生します。

    1. 「NDB Cluster」テーブルからの SELECT の場合: SELECTBLOB または TEXT カラムが含まれている場合、READ COMMITTED トランザクション分離レベルは読取りロック付きの読取りに変換されます。 これは一貫性を保証するために行われます。

    2. 一意キーのルックアップを使用して BLOB または TEXT データ型のいずれかを使用するカラムを取得し、1 つのトランザクション内で実行される SELECT の場合は、共有読み取りロックがトランザクションの期間中 (つまり、トランザクションがコミットまたは中止されるまで) そのテーブルに保持されます。

      インデックスまたはテーブルスキャンを使用するクエリーでは、BLOB または TEXT カラムを含む NDB テーブルが対象であっても、この問題は発生しません。

      たとえば、次の CREATE TABLE ステートメントによって定義されたテーブル t について考えます。

      CREATE TABLE t (
          a INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
          b INT NOT NULL,
          c INT NOT NULL,
          d TEXT,
          INDEX i(b),
          UNIQUE KEY u(c)
      ) ENGINE = NDB,

      t で次のクエリーを実行すると、一意キー検索が使用されるため、共有読取りロックが発生します:

      SELECT * FROM t WHERE c = 1;

      しかし、ここに示す 4 つのクエリーでは、いずれも共有読み取りロックは発生しません。

      SELECT * FROM t WHERE b = 1;
      
      SELECT * FROM t WHERE d = '1';
      
      SELECT * FROM t;
      
      SELECT b,c WHERE a = 1;

      その理由は、これら 4 つのクエリーのうち、1 つ目はインデックススキャンを使用し、2 つ目と 3 つ目はテーブルスキャンを使用し、4 つ目は (主キールックアップを使用していますが) BLOB または TEXT カラムの値を取得していないためです。

      BLOB または TEXT カラムを取得する一意キールックアップを使用するクエリーを回避するか、このようなクエリーを回避できない場合はトランザクションのコミットをできるだけあとで行うようにすると、共有読み取りロックによる問題を最小限に抑えることができます。

  • 一意キー参照とトランザクション分離.  一意インデックスは、内部的にメンテナンスされる非表示インデックステーブルを使用して NDB に実装されます。 一意インデックスを使用してユーザーが作成した NDB テーブルにアクセスすると、非表示のインデックステーブルが最初に読み取られて主キーが検索され、次にユーザーが作成したテーブルの読取りに使用されます。 この二重読取り操作中にインデックスが変更されないように、非表示のインデックステーブルで検出された行はロックされます。 ユーザー作成の NDB テーブルの一意インデックスによって参照される行が更新されると、非表示のインデックステーブルには、更新が実行されるトランザクションによる排他ロックが適用されます。 つまり、同じ (ユーザーが作成した) NDB テーブルに対する読取り操作は、更新が完了するまで待機する必要があります。 これは、読取り操作のトランザクションレベルが READ COMMITTED の場合でも当てはまります。

    潜在的なブロッキング読取りをバイパスするために使用できる回避策の 1 つは、読取りの実行時に SQL ノードが一意のインデックスを無視するように強制することです。 これを行うには、テーブルを読み取る SELECT ステートメントの一部として IGNORE INDEX インデックスヒントを使用します (セクション8.9.4「インデックスヒント」 を参照)。 MySQL サーバーでは、NDB で作成された一意のインデックスごとにシャドウ順序付きインデックスが作成されるため、かわりに順序付きインデックスを読み取ることができ、一意のインデックスアクセスロックが回避されます。 結果の読取りは、主キーによってコミットされた読取りと同じ一貫性があり、行の読取り時に最後にコミットされた値を返します。

    順序付けされたインデックスを介して読み取ると、クラスタ内のリソースの使用効率が低下し、待機時間が長くなる可能性があります。

    一意の値ではなく範囲をクエリーすることで、アクセスに一意のインデックスを使用しないようにすることもできます。

  • ロールバック.  部分的なトランザクションおよびトランザクションの部分的なロールバックはありません。 重複キーまたは同様のエラーが発生すると、トランザクション全体がロールバックされます。

    この動作は、個々のステートメントをロールバックできる InnoDB などのほかのトランザクション対応のストレージエンジンと異なります。

  • トランザクションとメモリー使用量.  この章のほかの場所で説明されているように、NDB Cluster は大きなトランザクションを適切に処理しません。多数の操作を含む単一の大きなトランザクションを試みるよりも、少数の操作で多数の小さなトランザクションを実行することをお勧めします。 特に考慮すべき点は、大規模なトランザクションが非常に大量のメモリーを必要とすることです。 このため、次のリストで説明するように、多数の MySQL ステートメントのトランザクション動作が影響を受けます:

    • TRUNCATE TABLE は、NDB テーブルに対して使用した場合、トランザクションになりません。 TRUNCATE TABLE でテーブルを空にできない場合は、成功するまでこれを再実行する必要があります。

    • DELETE FROM (WHERE 句が内場合も含む) は、トランザクションになります。 テーブルに非常に多くの行が含まれる場合は、複数の DELETE FROM ... LIMIT ... ステートメントを使用して削除操作をひとまとめにすると、パフォーマンスが向上することがあります。 テーブルを空にすることが目的である場合は、代わりに TRUNCATE TABLE を使用することをお勧めします。

    • LOAD DATA ステートメント.  NDB テーブルで使用する場合、LOAD DATA はトランザクション対応ではありません。

      重要

      LOAD DATA ステートメントを実行すると、NDB エンジンは不規則な間隔でコミットを実行し、通信ネットワークの使用率を向上させます。 このようなコミットが発生するタイミングを事前に知ることはできません。

    • ALTER TABLE とトランザクション.  ALTER TABLE の一部として NDB テーブルをコピーする場合、コピーの作成はトランザクションになりません。 (いずれにしても、コピーが削除されたときにこの操作はロールバックされます。)

  • トランザクションと COUNT() 関数.  NDB Cluster レプリケーションを使用する場合、レプリカ上の COUNT() 関数のトランザクションの一貫性を保証することはできません。 つまり、ソースで単一トランザクション内のテーブルの行数を変更する一連のステートメント (INSERTDELETE、またはその両方) を実行する場合、レプリカで SELECT COUNT(*) FROM table クエリーを実行すると中間結果が生成されることがあります。 これは、SELECT COUNT(...) がダーティー読み取りを行うために発生し、NDB ストレージエンジンのバグではありません。 (詳細は、Bug #31321 を参照してください。)


関連キーワード:  NDB, テーブル, ndbinfo, トランザクション, ndb, インデックス, 読取り, ノード, ロック, 実行