NDB Cluster には、トランザクションの処理に関していくつかの制限があります。 これらには、次のものが含まれます。
-
トランザクション分離レベル.
NDBCLUSTER
ストレージエンジンはREAD COMMITTED
トランザクション分離レベルのみをサポートします。 (たとえば、InnoDB
はREAD COMMITTED
、READ UNCOMMITTED
、REPEATABLE READ
、およびSERIALIZABLE
をサポートします。)NDB
はREAD COMMITTED
を行単位で実装する必要があることに注意してください。読取りリクエストが行を格納しているデータノードに到着すると、その時点で最後にコミットされたバージョンの行が返されます。コミットされていないデータが返されることはありませんが、複数の行を変更するトランザクションが同じ行を読み取るトランザクションと同時にコミットする場合、特定の行読取りリクエストを他のトランザクションのコミットの前または後に処理できるため、読取りを実行するトランザクションは、これらの間で異なる行に対して値の前、値の後、またはその両方を監視できます。
特定のトランザクションが変更前または変更後の値のみを読み取るようにするには、
SELECT ... LOCK IN SHARE MODE
を使用して行ロックを設定します。 このような場合、ロックは、所有しているトランザクションがコミットされるまで保持されます。 行ロックを使用すると、次の問題が発生することもあります:ロック待機タイムアウトエラーの頻度の向上と同時実行性の低下
コミットフェーズを必要とする読取りによるトランザクション処理オーバーヘッドの増加
使用可能な同時ロック数を使い果たす可能性があり、
MaxNoOfConcurrentOperations
によって制限されています
NDB
では、LOCK IN SHARE MODE
やFOR 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 つ発生します。「NDB Cluster」テーブルからの
SELECT
の場合:SELECT
にBLOB
またはTEXT
カラムが含まれている場合、READ COMMITTED
トランザクション分離レベルは読取りロック付きの読取りに変換されます。 これは一貫性を保証するために行われます。-
一意キーのルックアップを使用して
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()
関数のトランザクションの一貫性を保証することはできません。 つまり、ソースで単一トランザクション内のテーブルの行数を変更する一連のステートメント (INSERT
、DELETE
、またはその両方) を実行する場合、レプリカでSELECT COUNT(*) FROM
クエリーを実行すると中間結果が生成されることがあります。 これは、table
SELECT COUNT(...)
がダーティー読み取りを行うために発生し、NDB
ストレージエンジンのバグではありません。 (詳細は、Bug #31321 を参照してください。)