ロックのパーティション分割

大規模なコンピューター システムでは、頻繁に参照されるオブジェクトのロックがパフォーマンスのボトルネックになることがあります。これは、ロックの獲得と解放により、内部ロック リソースで競合が発生するためです。ロックのパーティション分割を行うと、単一のロック リソースが複数のロック リソースに分割されるので、ロックのパフォーマンスが向上します。この機能は、16 基以上の CPU を搭載しているシステムでのみ使用でき、自動的に有効になります。この機能を無効にすることはできません。パーティション分割できるのはオブジェクト ロックのみです。

注意

サブタイプがあるオブジェクト ロックはパーティション分割できません。詳細については、「sys.dm_tran_locks (Transact-SQL)」を参照してください。

ロックのパーティション分割について

ロック タスクでは、複数の共有リソースへのアクセスが行われます。これらのうち、次の 2 つがロックのパーティション分割によって最適化されます。

  • スピンロック : 行やテーブルなどのロック リソースへのアクセスを制御します。

    ロックのパーティション分割を行わない場合は、1 つのスピンロックにより単一のロック リソースのすべてのロック要求が管理されます。大量の処理が行われるシステムでは、スピンロックが使用できるようになるまでロック要求が待機するので、競合が発生する場合があります。この状況では、ロックの獲得がボトルネックになり、パフォーマンスが低下することがあります。

    単一のロック リソースの競合を減らすには、ロックのパーティション分割によって単一のロック リソースを複数のロック リソースに分割し、複数のスピンロックに負荷を分散します。

  • メモリ : ロック リソースの構造を格納するために使用されます。

    スピンロックが獲得されると、ロック構造がメモリに格納されます。その後、ロック構造へのアクセスが行われ、場合によっては変更されることがあります。ロックへのアクセスを複数のリソースに分散すると、CPU 間でメモリ ブロックを転送する必要がなくなり、パフォーマンスが向上します。

ロックのパーティション分割の実装と監視

ロックのパーティション分割は、16 基以上の CPU を搭載しているシステムでは既定で有効になっています。ロックのパーティション分割が有効になっていると、情報メッセージが SQL Server エラー ログに記録されます。

パーティション分割されたリソースのロックを獲得するときの規則を次に示します。

  • 単一のパーティションに対して獲得されるロック モードは、NL、SCH-S、IS、IU、および IX のみです。

  • 共有 (S) ロック、排他 (X) ロック、および NL、SCH-S、IS、IU、IX 以外のモードの他のロックは、パーティション ID が 0 のパーティションから、パーティション ID 順に獲得される必要があります。パーティション分割されたリソースでは、パーティションごとに別のロックが獲得されます。そのため、これらのパーティション分割されたリソースのロックでは、パーティション分割されていないリソースの同じモードのロックよりも多くのメモリが使用されます。メモリの増加量は、パーティションの数によって決まります。Windows パフォーマンス モニターの SQL Server ロック カウンターにより、パーティション分割されたロックとパーティション分割されていないロックによって使用されたメモリに関する情報が表示されます。

トランザクションは、開始したときにパーティションに割り当てられます。トランザクションでは、パーティション分割できるすべてのロック要求により、そのトランザクションに割り当てられたパーティションが使用されます。この方法により、複数のトランザクションから同じオブジェクトのロック リソースへのアクセスが異なるパーティションに分散されます。

sys.dm_tran_locks 動的管理ビューの resource_lock_partition 列により、ロックがパーティション分割されたリソースのロック パーティション ID が提供されます。詳細については、「sys.dm_tran_locks (Transact-SQL)」を参照してください。

SQL Server Profiler の Locks イベントでは、BigintData1 列により、ロックがパーティション分割されたリソースのロック パーティション ID が提供されます。

ロックのパーティション分割を使用した作業

次に、ロックのパーティション分割の例を示します。この例では、16 基の CPU を搭載しているコンピューター システムでのロックのパーティション分割の動作を示すために、2 つのトランザクションを 2 つの異なるセッションで実行します。

これらの Transact-SQL ステートメントにより、その後の例で使用するテスト オブジェクトが作成されます。

USE AdventureWorks2008R2;
GO

-- Create a test table.
CREATE TABLE TestTable
    (col1        int);
GO

-- Create a clustered index on the table.
CREATE CLUSTERED INDEX ci_TestTable 
    ON TestTable (col1);
GO

-- Populate the table.
INSERT INTO TestTable VALUES (1);
GO

例 A

セッション 1:

あるトランザクションで SELECT ステートメントが実行されます。HOLDLOCK ロック ヒントにより、このステートメントではテーブルのインテント共有 (IS) ロックが獲得および保持されます (ここでは、説明のため、行ロックとページ ロックは無視します)。IS ロックは、トランザクションに割り当てられたパーティションに対してのみ獲得されます。この例では、パーティション ID 7 に対して IS ロックが獲得されるものとします。

-- Start a transaction.
BEGIN TRANSACTION
    -- This SELECT statement will acquire an IS lock on the table.
    SELECT col1
        FROM TestTable
        WITH (HOLDLOCK);

セッション 2:

トランザクションが開始され、このトランザクションで実行されている SELECT ステートメントにより、テーブルの共有 (S) ロックが獲得および保持されます。S ロックはすべてのパーティションに対して獲得されるため、複数のテーブル ロック (各パーティションに 1 つのロック) が存在することになります。たとえば、16 基の CPU を搭載しているシステムで、ロック パーティション ID 0 ~ 15 に 16 個の S ロックが発行されるとします。S ロックは、セッション 1 のトランザクションによりパーティション ID 7 に対して保持されている IS ロックと互換性があるので、トランザクション間のブロッキングは発生しません。

BEGIN TRANSACTION
    SELECT col1
        FROM TestTable
        WITH (TABLOCK, HOLDLOCK);

セッション 1:

セッション 1 において依然としてアクティブなトランザクションで次の SELECT ステートメントが実行されます。排他 (X) テーブル ロック ヒントにより、このトランザクションではテーブルの X ロックの獲得が試行されます。ただし、セッション 2 のトランザクションで保持されている S ロックにより、パーティション ID 0 で X ロックがブロックされます。

    SELECT col1
        FROM TestTable
        WITH (TABLOCKX);

例 B

セッション 1:

あるトランザクションで SELECT ステートメントが実行されます。HOLDLOCK ロック ヒントにより、このステートメントではテーブルのインテント共有 (IS) ロックが獲得および保持されます (ここでは、説明のため、行ロックとページ ロックは無視します)。IS ロックは、トランザクションに割り当てられたパーティションに対してのみ獲得されます。この例では、パーティション ID 6 に対して IS ロックが獲得されるものとします。

-- Start a transaction.
BEGIN TRANSACTION
    -- This SELECT statement will acquire an IS lock on the table.
    SELECT col1
        FROM TestTable
        WITH (HOLDLOCK);

セッション 2:

あるトランザクションで SELECT ステートメントが実行されます。TABLOCKX ロック ヒントにより、このトランザクションではテーブルに対して排他 (X) ロックの獲得が試行されます。X ロックはパーティション ID が 0 のパーティションから、パーティション ID 順に獲得される必要があることに注意してください。X ロックはパーティション ID 0 ~ 5 のパーティションに対して獲得されますが、パーティション ID 6 に対して獲得された IS ロックによりブロックされます。

X ロックが獲得されていないパーティション ID 7 ~ 15 に対しては、他のトランザクションがロックの獲得を続行できます。

BEGIN TRANSACTION
    SELECT col1
        FROM TestTable
        WITH (TABLOCKX, HOLDLOCK);