sql >> データベース >  >> RDS >> Sqlserver

SQLServerロックの主な概念

    この投稿では、SQL Serverのロックメカニズムと、SQLServerの標準の動的管理ビューを使用してSQLServerのロックを監視する方法について説明します。 SQL Serverのロックアーキテクチャについて説明する前に、ACID(Atomicity、Consistency、Isolation、およびDurability)データベースとは何かについて説明しましょう。 ACIDデータベースは、データベース理論として説明できます。データベースがリレーショナルデータベースと呼ばれる場合、そのデータベースは、Atomicity、Consistency、Isolation、およびDurabilityの要件を満たす必要があります。次に、これらの要件について簡単に説明します。

    アトミシティ :これは、トランザクションプロセスの主な機能として説明する不可分性の原則を反映しています。トランザクションブロックを放置することはできません。残りのトランザクションブロックの半分は、データの不整合を引き起こします。トランザクション全体が実行されるか、トランザクションが最初に戻ります。つまり、トランザクションによって行われたすべての変更は取り消され、以前の状態に戻ります。

    一貫性 :非分割性ルールの下部構造を設定するルールがあります。トランザクションデータは一貫性を提供する必要があります。つまり、トランザクションで更新操作を実行する場合は、残りのすべてのトランザクションを実行するか、更新操作をキャンセルする必要があります。このデータは一貫性の観点から非常に重要です。

    分離 :これは、各トランザクションデータベースの要求パケットです。要求パケットによって行われた変更は、完了する前に別のトランザクションに表示される必要があります。各トランザクションは個別に処理する必要があります。すべてのトランザクションは、発生後に別のトランザクションから見えるようにする必要があります。

    耐久性: トランザクションは、データを使用して複雑な操作を実行できます。これらすべてのトランザクションを保護するには、トランザクションエラーに耐える必要があります。 SQL Serverで発生する可能性のあるシステムの問題は、電源障害、オペレーティングシステム、またはその他のソフトウェアに起因するエラーに対して準備し、回復力を持たせる必要があります。

    トランザクション: トランザクションは、プロセスの最小スタックであり、小さな部分に分割することはできません。また、トランザクションプロセスの一部のグループを順番に実行できますが、Atomicityの原則で説明したように、トランザクションの1つでも失敗すると、すべてのトランザクションブロックが失敗します。

    ロック: ロックは、データの一貫性を確保するためのメカニズムです。 SQL Serverは、トランザクションの開始時にオブジェクトをロックします。トランザクションが完了すると、SQLServerはロックされたオブジェクトを解放します。このロックモードは、SQLServerのプロセスタイプと分離レベルに応じて変更できます。これらのロックモードは次のとおりです。

    ロック階層: SQL Serverには、この階層内のロックオブジェクトを取得するロック階層があります。データベースは階層の最上位にあり、行は最下位にあります。次の画像は、SQLServerのロック階層を示しています。

    共有(S)ロック: このロックタイプは、オブジェクトを読み取る必要がある場合に発生します。このロックタイプはあまり問題になりません。

    排他的(X)ロック: このロックタイプが発生すると、他のトランザクションがロックされたオブジェクトを変更またはアクセスできないようにするために発生します。

    更新(U)ロック: このロックタイプは排他ロックに似ていますが、いくつかの違いがあります。更新操作は、読み取りフェーズと書き込みフェーズの異なるフェーズに分割できます。読み取りフェーズ中、SQL Serverは、他のトランザクションがこのオブジェクトにアクセスして変更されることを望んでいません。このため、SQLServerは更新ロックを使用します。

    インテントロック: インテントロックは、SQL Serverがロック階層の下位にあるリソースの一部で共有(S)ロックまたは排他(X)ロックを取得する場合に発生します。実際には、SQL Serverがページまたは行のロックを取得する場合、テーブルにインテントロックが必要です。

    これらすべての簡単な説明の後、ロックを識別する方法に対する答えを見つけようとします。 SQL Serverは、メトリックにアクセスするための多くの動的管理ビューを提供します。 SQL Serverのロックを特定するには、 sys.dm_tran_locksを使用できます。 見る。このビューでは、現在アクティブなロックマネージャーリソースに関する多くの情報を見つけることができます。

    最初の例では、インデックスを含まないデモテーブルを作成し、このデモテーブルを更新してみます。

    CREATE TABLE TestBlock
    (Id INT ,
    Nm VARCHAR(100))
    
    INSERT INTO TestBlock
    values(1,'CodingSight')
    In this step, we will create an open transaction and analyze the locked resources.
    BEGIN TRAN
    UPDATE TestBlock SET   Nm='NewValue_CodingSight' where Id=1
    select @@SPID
    

    次に、sys.dm_tran_lockビューを確認します。

    select * from sys.dm_tran_locks  WHERE request_session_id=74

    このビューは、アクティブなロックリソースに関する多くの情報を返します。ただし、このビューの一部のデータを理解することはできません。このため、 sys.dm_tran_locksに参加する必要があります 他のビューに表示します。

    SELECT dm_tran_locks.request_session_id,
           dm_tran_locks.resource_database_id,
           DB_NAME(dm_tran_locks.resource_database_id) AS dbname,
           CASE
               WHEN resource_type = 'OBJECT'
                   THEN OBJECT_NAME(dm_tran_locks.resource_associated_entity_id)
               ELSE OBJECT_NAME(partitions.OBJECT_ID)
           END AS ObjectName,
           partitions.index_id,
           indexes.name AS index_name,
           dm_tran_locks.resource_type,
           dm_tran_locks.resource_description,
           dm_tran_locks.resource_associated_entity_id,
           dm_tran_locks.request_mode,
           dm_tran_locks.request_status
    FROM sys.dm_tran_locks
    LEFT JOIN sys.partitions ON partitions.hobt_id = dm_tran_locks.resource_associated_entity_id
    LEFT JOIN sys.indexes ON indexes.OBJECT_ID = partitions.OBJECT_ID AND indexes.index_id = partitions.index_id
    WHERE resource_associated_entity_id > 0
      AND resource_database_id = DB_ID()
     and request_session_id=74
    ORDER BY request_session_id, resource_associated_entity_id
    

    上の画像では、ロックされたリソースを確認できます。 SQL Serverは、その行の排他ロックを取得します。 ( RID :ヒープ内の単一の行をロックするために使用される行識別子)同時に、SQLServerはページとTestBlockのインテント排他ロックを取得します テーブル。これは、SQL Serverがロックを解放するまで、他のプロセスがこのリソースを読み取ることができないことを意味します。これは、SQLServerの基本的なロックメカニズムです。

    次に、テストテーブルにいくつかの合成データを入力します。

    TRUNCATE TABLE 	  TestBlock
    DECLARE @K AS INT=0
    WHILE @K <8000
    BEGIN
    INSERT TestBlock VALUES(@K, CAST(@K AS varchar(10)) + ' Value' )
    SET @[email protected]+1
     END
    After completing this step, we will run two queries and check the sys.dm_tran_locks view.
    BEGIN TRAN
     UPDATE TestBlock  set Nm ='New_Value' where Id<5000
    

    上記のクエリでは、SQLServerはすべての行の排他ロックを取得します。次に、別のクエリを実行します。

    BEGIN TRAN
     UPDATE TestBlock  set Nm ='New_Value' where Id<7000
    

    上記のクエリでは、SQL Serverはテーブルに排他ロックを作成します。これは、SQLServerが更新されるこれらの行に対して多くのRIDロックを取得しようとするためです。この場合、データベースエンジンで多くのリソースが消費されます。したがって、SQL Serverは、この排他ロックをロック階層内の上位オブジェクトに自動的に移動します。このメカニズムをロックエスカレーションと定義します。ロックエスカレーションはテーブルレベルで変更できます。

    ALTER TABLE XX_TableName
    SET
    (
    	LOCK_ESCALATION = AUTO -- or TABLE or DISABLE
    )
    GO
    

    ロックのエスカレーションについていくつかメモを追加したいと思います。パーティションテーブルがある場合は、エスカレーションをパーティションレベルに設定できます。

    このステップでは、AdventureWorksHumanResourcesテーブルにロックを作成するクエリを実行します。このテーブルには、クラスター化インデックスと非クラスター化インデックスがあります。

    BEGIN TRAN	
    UPDATE 	  [HumanResources].[Department] SET Name='NewName' where DepartmentID=1
    

    以下の結果ペインに表示されているように、トランザクションはPK_Department_DepartmentIDクラスターインデックスキーの排他ロックを取得し、AK_Department_Name非クラスター化インデックスキーの排他ロックも取得します。これで、「SQLServerが非クラスター化インデックスをロックする理由」という質問をすることができます。

    名前 列はAK_Department_Name非クラスター化インデックスでインデックス付けされており、名前を変更しようとしています 桁。この場合、SQLServerはその列の非クラスター化インデックスを変更する必要があります。非クラスター化インデックスリーフレベルには、ソートされたすべてのKEY値が含まれます。

    結論

    この記事では、SQL Serverのロックメカニズムの主要な行について説明し、sys.dm_tran_locksの使用について検討しました。 sys.dm_tran_locksビューは、現在アクティブなロックリソースに関する多くの情報を返します。グーグルすると、このビューに関する多くのサンプルクエリを見つけることができます。

    参考資料

    SQLServerトランザクションロックおよび行バージョン管理ガイド

    SQL Server、オブジェクトのロック


    1. Oracleで主キーを持つ重複行を見つける11の方法

    2. django ORMを使用して、外部キーフィールドで2つのテーブルをどのように結合しますか?

    3. SQLServerで「datediff関数がオーバーフローを引き起こしました」エラーを修正する方法

    4. SQLでは、2つのテーブルが相互に参照しても問題ありませんか?