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

SQLServerでのNOLOCKヒントの基本と使用法

    SQL Serverのロックメカニズムの主な考え方は、トランザクションの一貫性を制御することです。この原則によれば、プロセスが挿入、削除、または更新操作を実行する場合、SQL Serverエンジンは1つまたは複数の行をロックし、トランザクションが完了するまで別のプロセスを許可しません。状況によっては、このロックメカニズムにより、同時プロセスの圧力が高くなるなどのパフォーマンスの問題が発生する可能性があります。そのため、データベースでデッドロック(2つのトランザクションが同じデータに同時にアクセスする同時実行の問題)の問題が発生する可能性があります。この記事では、NOLOCKヒントを使用してロックの問題を回避する方法に焦点を当てます。まず、NOLOCKヒントがダーティリーディングを引き起こす可能性があるため、ダーティリードの方法論の主な要点と詳細を学びましょう。

    ダーティリード: この読み取り方法では、読み取りプロセスはコミットされていないデータを読み取り、読み取りプロセスは開いているトランザクションを考慮しないため、ロックによって読み取りプロセスで問題が発生することはありません。結果として、このタイプの読み取りはロックの問題を減らします。ただし、ダーティリーディングは、SELECTステートメントの結果セットに不整合の問題を引き起こす可能性があるため、ダーティリーディングの方法には長所と短所があります。すでに述べたように、この結果セットにはコミットされていないトランザクションデータが含まれる可能性があるため、この種の読み取りを行うことを決定する際には、ダーティな読み取りを考慮する必要があります。これらの行はロールバックされる可能性があるため、ダーティ読み取り中に作成する行の精度については確信が持てません。一方、このタイプの読み取りにより、ロックの問題を回避し、SQLServerのパフォーマンスを向上させることができます。

    NOLOCK: SQL Serverの既定の分離レベルは[読み取りコミット]であり、この分離レベルでは、SQL Serverは、コミットされていないトランザクションによってロックされているロックされたオブジェクトの読み取りを許可しません。さらに、これらのロックされたオブジェクトは、ロックのエスカレーションに応じて変更できます。

    注:このSQL Serverロックの主な概念の記事では、ロックとロックのエスカレーションについて詳しく説明しています。

    2人のデータベースユーザーがいて、これらのユーザーがデータベースに対して更新と選択操作を実行したいとします。最初のユーザーがテーブル内の特定の行の更新を開始し、次に他のユーザーが同じ行を読み取りたいと考えています。これらの2人のユーザーは、次の更新および選択ステートメントを実行します。これを下の画像に示します。

    この場合、user2は少なくとも10秒間待機してから、トランザクションはuser1によってロールバックされます。ロックされた行はuser1によって解放されるため、user2は緑色の行を読み取ることができます。これは、SQLServer読み取りコミット分離レベルのデフォルトの動作です。

    ここで、SQLServerでこのケースを示します。まず、FruitSalesテーブルとその行を作成します。

     CREATE TABLE FruitSales(Id INT IDENTITY(1,1)PRIMARY KEY、[Name] Varchar(20)、SalesTotal Float)GOINSERT INTO FruitSales VALUES('Apple'、10)、('Orange'、8)、( 'バナナ'、2)

    この手順では、2つのSQL Server Management Studioクエリウィンドウを開き、user1クエリを実行してから、user2クエリを実行します。

     --- USER1 ---- BEGIN TRAN UPDATE FruitSales SET SalesTotal =20 WHERE Id =2 WAITFOR DELAY '00:00:10' ROLLBACK TRANSACTION --- USER2 ---- SET STATISTICS TIME ONSELECT * FROM FruitSales WHERE Id =2 

    上の画像でわかるように、2番目のクエリはuser1トランザクションのロールバックまで待機します。

    次に、NOLOCKのヒントと使用法の詳細について説明します。 NOLOCKヒントは、データベース開発者および管理者がSQLServerデータベースのロックの問題を排除するために使用する最も一般的なテーブルヒントです。 NOLOCKテーブルヒントを使用すると、開いているトランザクションによってロックされているロックされたオブジェクト(行、ページ、またはテーブル)を読み取ることができます。 NOLOCKヒントは、SQL Serverクエリオプティマイザのデフォルトの動作を上書きして、selectステートメントがロックされたオブジェクトを読み取れるようにします。

    ここで、NOLOCKヒントをuser2 selectステートメントに追加してから、user1更新を開始してから、user2selectステートメントを実行します。

     --- USER1 ---- BEGIN TRAN UPDATE FruitSales SET SalesTotal =20 WHERE Id =2 WAITFOR DELAY '00:00:10' ROLLBACK TRANSACTION --- USER2 ---- SET STATISTICS TIME ONSELECT * FROM FruitSales WITH (NOLOCK)WHERE Id =2 

    このステップでは、user2selectステートメントのNOLOCKヒントに影響を与える方法を説明します。 User1は明示的なトランザクションで更新されたステートメントを実行し、次にuser2はselectステートメントを実行し、結果セットはトランザクションの完了を遅らせることなく戻ります。これがNOLOCKの主なアイデアであり、ロックされたオブジェクトを読み取ります。

    ここで、selectステートメントの結果セットに焦点を当てます。 user2 selectステートメントはSalesTotal値20を取得しましたが、SalesTotalの実際の値は8のままです。selectステートメントでNOLOCKテーブルヒントを使用している場合、このタイプの不正確なデータ結果に直面する可能性があることに注意してください。

    ヒント: 「WITH」キーワードは非推奨の機能であるため、新しいデータベース開発では使用せず、現在の開発では「WITH」キーワードを削除することをお勧めします。 「WITH」キーワードなしでNOLOCKヒントの使用法を見つけることができます。

     --- USER1 ---- BEGIN TRAN UPDATE FruitSales SET SalesTotal =20 WHERE Id =2 WAITFOR DELAY '00:00:10' ROLLBACK TRANSACTIONSELECT * FROM FruitSales WHERE Id =2 --USER2 --- SELECT * FROM FruitSales(NOLOCK)WHERE Id =2 

    さらに、READUNCOMMITTEDテーブルヒントはNOLOCKヒントと同等であり、NOLOCKヒントの代わりにREADUNCOMMITTEDヒントを使用できます。

     SELECT * FROM FruitSales(READUNCOMMITTED)WHERE Id =2 

    それでも、NOLOCKヒントには、ロックバリアを通過できない特定のケースがあります。テーブルを変更するプロセスがある場合、NOLOCKヒントはこのタイプのロックを克服できず、読み取り操作を続行できません。この問題の理由は、NOLOCKヒントがSch-S(スキーマ安定性)ロックを取得し、ALTER TABLEステートメントがSCH-M(スキーマ変更)ロックを取得するため、競合が発生するためです。

    最初に、次のクエリを使用して、FruitSalesテーブルのObject_Idを学習します。

     select OBJECT_ID('FruitSales')

    次のuser1クエリを実行してから、user2クエリを実行します。その結果、user2クエリはuser1テーブル変更プロセスの完了を遅らせます。

     --USER1 --- BEGIN TRANALTER TABLE FruitSalesADD ColorofFruit varchar(200)WAITFOR DELAY '00:00:35GOCOMMIT TRAN --USER2 --- SELECT * FROM FruitSales(NOLOCK)WHERE Id =2 

    新しいクエリウィンドウを開き、次のクエリを実行します。このクエリは、user1およびuser2クエリのロックタイプを見つけるのに役立ちます。

     SELECT Resource_type、Resource_database_id、Resource_description、Resource_located_entity_id、Resource_lock_partition、Request_mode、Request_type、Request_status、Request_session_id、Request_request_id、Request_owner_type、Request_owner_id、Lock_owner_addressFROM sys.dm_tran_lockswhere resource_truck_ent_ 

    次に、SCH-MとSCH-Sの相互作用のロック互換性マトリックスを確認します。マトリックスは、SCH-MとSCH-Sの相互作用が競合を引き起こすことを示しています。

    結論

    この記事では、ダーティリーディングプロセスとNOLOCKヒントについて説明しました。 NOLOCKヒントを使用することは、ロックされたページを読み取るための効果的な方法ですが、いくつかの長所と短所もあります。このため、使用する前にNOLOCKヒントを検討する必要があります。

    参考資料

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

    ヒント(Transact-SQL)–表

    トランザクション分離レベルの設定(Transact-SQL)


    1. ORA-12704:文字セットの不一致

    2. MySQL-WHERE句でCOUNT(*)を使用

    3. 19.3PDBクローズORA-65107ORA-16078

    4. Oracle SQL*Plusの使用方法