何人かのユーザーやいくつかのアプリケーションが同時に、Teradata Databaseに格納されているデータにアクセスすることができます。
ロック マネージャは、各トランザクションによってアクセスされているデータベース オブジェクトのロックを管理して、トランザクションがその作業をコミットまたはロールバックするときにそれらのロックを解放することにより、Teradata Databaseに同時並行制御を強制します。この制御によって、すべてのユーザーに対してデータの一貫性が保証されます。グローバル デッドロックの回避と検出の例外により、Teradata Databaseでのロックはグローバルにではなく、個別のAMPによってローカルに管理されることに注意してください。
グローバル デッドロック検出の詳細については、デッドロックを参照してください。
構文解析プログラムはリクエストのロックを自動的に定義しますが、ロックを格上げしたり、場合によってはSQL LOCKINGリクエスト修飾子を使用して明示的に格下げしたりすることができます。詳細については、<Teradata Vantage™ - SQLデータ操作言語、B035-1146>の「LOCKINGリクエスト修飾子」を参照してください。
ロックに関する考慮事項
Teradata Databaseは、最大限の並列性を維持しながらもデータベースの整合性を確保するために、常にできるだけ最も制約の少ないレベルおよび重大度でデータベース オブジェクトをロックするようにしています。
(これは、厳密には、HUTロックには当てはまりません。HUTロックでは、同じロック レベルおよび重大度が、常に所定のArchive/Recoveryユーティリティ コマンドに使用されます。HUTロックの詳細については、<Teradata® Archive/Recovery Utilityリファレンス、B035-2412>を参照してください。)
2フェーズ ロックが機能するしくみによって、ユーザーはロックがいつ解放されるかを制御できません(デ-タベ-ス ロック、2フェーズ ロック、および逐次性を参照)。
- テーブルを所有するデータベース
- テーブル自体
- テーブルのいずれかのパーティションまたは行
- テーブルの所有者データベース
- 行の親テーブル
- テーブルのパーティション
- 行ハッシュ自体
いずれの場合にも、競合するロックが解放されるまで、リクエストが待ち行列に入れられます。
ロック マネージャのリソースを使い果たす可能性があります。ロック マネージャのリソースが使い果たされたときにロックを要求するトランザクションがあると、Transaction Managerはトランザクションをアボートします。そのような場合には、DDLリクエストに対する行ハッシュ レベルのロックを無効にすることができます。また、AMPごとに一度に掛けられるロック数の制限があります。
アプリケーションでトランザクションを開始してから、このトランザクションを閉じずに多数の単一行の更新を行なうと、少なくとも1つのAMPロック テーブルにより最大容量が占有されるようになります。これは、通常、ANSIセッション モードのトランザクションに発生しますが、その限りではありません。
このようなAMPロック テーブルのオーバーフローは、最初に基礎となるデータベース オブジェクト上の1つ以上のロックを獲得しなければリクエストを開始できないため、他のトランザクションにも影響します。しばらくすると、ロックを獲得できなかったトランザクションはアボートし、システムがクラッシュする場合もあります。
DBS制御フィールドMaxRowHashBlocksPercent (詳細については、<Teradata Vantage™ - データベース ユーティリティ、B035-1102>を参照)を使用して、ロック マネージャが各トランザクションに許可する行ハッシュ レベルのロックの最大数を制御できます。
このフィールドのデフォルトは、AMPロック テーブルでサポートできる制御ブロックの、合計数の50パーセントです。MaxRowHashBlocksPercentの値は、最大で100%に設定して、システムのワークロードが必要とする行ハッシュ レベル ロックの数を収めることができます。
Teradata Databaseは、獲得する行ハッシュ レベルのロックの数がMaxRowHashBlocksPercentで定義されたしきい値を超えた場合は、自動的にトランザクションをアボートします。これが発生した場合でも、他のトランザクションには影響しません。トランザクションにより保持される行ハッシュ レベルのロックに対するこのような制御は、ANSIセッション モードおよび明示的なTeradataセッション モードのトランザクションに対してのみ適用されます。暗黙的なTeradataモードの各リクエストは、それ自体がトランザクションであり、トランザクションがコミットまたはロールバックされるとすぐにシステムによりそのロックが解除されるため、暗黙的なTeradataモードのトランザクションには影響しません。
Lock Display(lokdisp)ユーリティティ(<Teradata Vantage™ - データベース ユーティリティ、B035-1102>を参照)またはロック ビューアViewpointポートレットを使用すれば、設定済みのすべてのロックを確認して、他のユーザーのどのロックが自分のトランザクションをブロックしているかを調べることができます。
一度設定するとロックはトランザクションが完了するまで解放されません。
- トランザクションがコミットする。
- トランザクションがアボートされ、ロールバックを完了したとき
ABORT/ROLLBACK文、非同期アボート、失敗応答、タイムアウト、ログオフ、およびシステムの再始動は、トランザクションのアボートが発生する原因となることがあります。
トランザクション終了後もスプールが存在する可能性があるので、このロック解放は、リクエストに対する応答を受け取るかどうかに関係なく生じます。さらにこれらの各アクションは、一時ジャーナルを削除して、開いているカーソルを閉じます。
システムの再始動中に、処理が破壊されたときに処理中であった更新トランザクションだけがアボートされ、ロールバックされる必要があります。それらのトランザクションに設定されたWRITEおよびEXCLUSIVEロックは、トランザクションがロールバックされるまでそのまま残ります。
データベース トランザクション ロックの場合とは異なり、HUTロックは明示的に解放する必要があります。HUTロックの詳細については、<Teradata® Archive/Recovery Utilityリファレンス、B035-2412>を参照してください。
ロックの保持期間を最短にするための複文リクエストの使用
可能な場合は、同じテーブルまたはビューのセットにアクセスする個別のリクエストを、複文リクエストを使用して1つにまとめてください。例えば、あるテーブルに行を挿入し、それと同じテーブルの別の行を更新してから、そのテーブルのさらに別の行を削除するとします。
これを実行するために、次の個別のリクエストを使用することもできます。このリクエストでは、行をcust_rateに挿入し、cust_rateの既存の行を更新して、それらとは別の行をcust_rateから削除します。また、cust_rateに何らかの操作を実行してから、その操作で処理したばかりのcust_rateの行を更新するinit_custマクロを実行します。
INSERT INTO cust_rate VALUES (123, “GOOD’); UPDATE cust_rate SET cust_rating=’FAIR’ WHERE cust_id=456; DELETE FROM cust_rate WHERE cust_id=789; EXECUTE init_cust (9999); UPDATE cust_rate SET cust_rating=’FAIR’ WHERE cust_id=9999;
この場合は、リクエストごとに1つのSQL文のみを実行することになります。これは、リクエストのブロックを最小化するには非効率的です。
その代わりに、これと同じSQLを実行する複文リクエストを実行したとすると、Teradata Databaseはcust_rateに対して行ハッシュ レベルのWRITEロックを2回掛けるだけで済み、そのテーブルを解放することで同時実行中の他のトランザクションが素早くアクセスできるようになります。この複文リクエストは、そのリクエストが最適な順序になるように、次の順序で実行されます。
INSERT INTO cust_rate VALUES (123, ‘GOOD’) ; UPDATE cust_rate SET cust_rating=’FAIR’ WHERE cust_id=456 ; DELETE FROM cust_rate WHERE cust_id=789; EXECUTE init_cust (9999) ; UPDATE cust_rate SET cust_rating=’FAIR’ WHERE cust_id=9999;
BEGIN TRANSACTION ; INSERT INTO cust_rate VALUES (123, ‘GOOD’) ; UPDATE cust_rate SET cust_rating=’FAIR’ WHERE cust_id=456 ; DELETE FROM cust_rate WHERE cust_id=789; EXECUTE init_cust (9999) ; UPDATE cust_rate SET cust_rating=’FAIR’ WHERE cust_id=9999; ; END TRANSACTION;