4

最終決定を理解することはビジネス上の決定です。SQL 2008 R2 で実行されている NOLOCK と READPAST の間の精度に関する考慮事項は何ですか? 事業領域との変更について話し合う前に、理解を深めたいと思います。

管理レポート用のデータ ビューを作成するために使用される多くのクエリを継承しました。「WITH (NOLOCK)」は自由に使用されますが、一貫性がありません。読み取られるデータは、頻繁に更新される広く使用されているアプリケーションの運用サーバーからのものです。SQL 2005 サーバーから SQL 2008 R2 サーバーに移行しています。これらのレポートは、アーカイブ サーバー上の 24 時間前のデータよりも新しいデータを必要とします。NOLOCK の使用は、過去の決定を示唆しています。競合の可能性があり、多少の精度の低下は許容されます。データは、人間の認識/意思決定のためにダッシュボードに入力するために使用されます。

すべてのクエリは SELECT であり、データ ビューのログインには読み取り専用のアクセス権があります。クエリの大部分は、いくつかの 2 つまたは 3 つのテーブル結合を含む単一のテーブルです。低レベルの結合を考えると、WITH () は SET TRANSACTION ISOLATION LEVEL {} よりも適切な選択のようです。

Table Hints (Transact-SQL) http://msdn.microsoft.com/en-us/library/ms187373.aspx (および SO に関する複数の質問) は、NOLOCK および/または READUNCOMMITTED には重複した読み取りの問題がある可能性が高いと述べています。ロックされたレコードの欠落に加えて。

READPAST は、重複の可能性なしにロックされたレコードのみを見逃すため、より正確に見えます。しかし、ロックされたレコードの欠落のレベルが、それと NOLOCK の間で一貫しているかどうかはわかりません。

この 2 つを比較した Tim Chapman による優れた記事がありますが、これは 2007 年に書かれたものであり、ほとんどのコメントは 2000 年と 2005 年を中心に展開されており、1 つのコメントは 2008 R2 で READPAST に問題があることを示しています

参考文献

SELECT ステートメントでの NOLOCK ヒントの効果

"with (nolock)" を使用する必要がある場合

SQL Server での NOLOCK および READPAST テーブル ヒントの使用 (Tim Chapman 著)

編集:

スナップショット分離は、以下の 2 つの回答で提案されています。スナップショット分離は DB の設定に依存します。この Q/A https://serverfault.com/questions/117104/how-can-i-tell-if-snapshot-isolation-is-turned-onは、どの設定を確認するかを説明していますデータベースに配置されています。無効になっていることがわかりました。主要なアプリケーション データベースからのレポートを読んでいます。設定を変更することはオプションではありません。+- 数パーセントの精度は許容できますが、アプリケーション (OLTP) への影響は許容できません。ほとんどの単純なクエリではロックを考慮する必要はありませんが、極端な場合にはロックを考慮する必要があります。SQL 2005 のスナップショット分離の出現により、SQL 2008 以降での NOLOCK および READPAST の動作に関する情報はほとんどありません。それでも、それらは私の唯一の選択肢のままです。

4

3 に答える 3

8

考慮に値するより良いオプションは、データベース自体に対して READ COMMITTED SNAPSHOT を有効にすることです。これは、tempdb のバージョン管理を使用して、トランザクションの開始時のテーブルの状態をキャプチャします。

http://www.brentozar.com/archive/2013/01/implementing-snapshot-or-read-committed-snapshot-isolation-in-sql-には、NOLOCK、READPAST などのさまざまな側面に関する非常に優れた読み物があります。サーバーガイド/

WITH (NOLOCK)テーブルから選択しているときに誰かがテーブルを更新している場合、誤った結果が返される可能性があります。テーブルの読み取り中に挿入の結果としてページ分割が発生し、新しいページがたまたま読み取ったポイントを超えている場合WITH (NOLOCK)、古いページから既に行が返され、重複した行が返されます新しいページから。(NOLOCK)これは、が悪い理由の 1 つの例にすぎません。

WITH (READPAST)テーブルからの読み取り中に更新または挿入されるレコードをスキップします。どちらのオプションも、ビジー状態のデータベースには適していません。

のデータベース設定を変更できないと述べた質問に対する最近の編集に照らしてREAD COMMITTED SNAPSHOT、おそらく、ストアド プロシージャを使用してレポートのデータを収集し、ストアド プロシージャを使用してストアド プロシージャの先頭にトランザクション分離レベルを設定することを検討する必要がありますSET TRANSACTION ISOLATION LEVEL SNAPSHOT;。これを行うには、データベース オプション「スナップショット分離を許可する」を変更する必要があります。

SQL Server Books Online から:

スナップショット

トランザクション内の任意のステートメントによって読み取られるデータが、トランザクションの開始時に存在したデータのトランザクション的に一貫性のあるバージョンになることを指定します。トランザクションは、トランザクションの開始前にコミットされたデータ変更のみを認識できます。現在のトランザクションの開始後に他のトランザクションによって行われたデータ変更は、現在のトランザクションで実行されているステートメントには表示されません。その効果は、トランザクション内のステートメントが、トランザクションの開始時に存在していたコミットされたデータのスナップショットを取得するかのようです。

データベースが回復されている場合を除いて、SNAPSHOT トランザクションはデータの読み取り時にロックを要求しません。データを読み取る SNAPSHOT トランザクションは、他のトランザクションがデータを書き込むことをブロックしません。データを書き込むトランザクションは、SNAPSHOT トランザクションがデータを読み取ることをブロックしません。

データベース リカバリのロールバック フェーズ中に、ロールバックされている別のトランザクションによってロックされているデータを読み取ろうとすると、SNAPSHOT トランザクションはロックを要求します。SNAPSHOT トランザクションは、そのトランザクションがロールバックされるまでブロックされます。ロックは、付与された直後に解放されます。

SNAPSHOT 分離レベルを使用するトランザクションを開始する前に、ALLOW_SNAPSHOT_ISOLATION データベース オプションを ON に設定する必要があります。SNAPSHOT 分離レベルを使用するトランザクションが複数のデータベースのデータにアクセスする場合、各データベースで ALLOW_SNAPSHOT_ISOLATION を ON に設定する必要があります。

別の分離レベルで開始されたトランザクションを SNAPSHOT 分離レベルに設定することはできません。これを行うと、トランザクションが中止されます。トランザクションが SNAPSHOT 分離レベルで開始された場合、それを別の分離レベルに変更してから、SNAPSHOT に戻すことができます。トランザクションは、データに初めてアクセスしたときに開始されます。

SNAPSHOT 分離レベルで実行されているトランザクションは、そのトランザクションによって行われた変更を表示できます。たとえば、トランザクションがテーブルに対して UPDATE を実行し、同じテーブルに対して SELECT ステートメントを発行すると、変更されたデータが結果セットに含まれます。

于 2013-04-02T17:35:19.477 に答える
3

NOLOCK重複したデータが読み取られたり、データが失われたり、クエリが実際に失敗してエラー メッセージが表示されたりする可能性があります (「データ移動」を伴うもの)。

一方、NONLOCKクエリ以外でも重複データやミスデータを読み取ることができます。これは、データベースの一貫したスナップショットではありません。違いは、コミットされていないデータを読み取らず、決して失敗しないことです。

問題NOLOCKは、ほとんどの場合、ランダムに失敗する可能性があるため、再試行する必要があることです。また、誤ったデータが読み取られる可能性がわずかに高くなります。

NOLOCKテーブル スキャンを実行する場合、大きな利点があります。SQL Server は、インデックス順スキャンの代わりに割り当て順スキャンを使用できます。TABLOCK同じ効果があります。これは、断片化が存在する場合に大幅な高速化になる可能性があります。

これらの問題をすべて取り除くため、スナップショット分離レベルを使用することを検討してください。他にもいくつかのトレードオフがあり、割り当て順序のスキャンは得られません。しかし、ロックの問題を永久的かつ包括的に取り除きます。

于 2013-04-02T17:42:16.633 に答える
2

SQLQueryStress http://www.datamanipulation.net/sqlquerystress/ (これは非常に使いやすい素晴らしいツールです) でストレス テストを行った後、自分の質問に答えます。SQLQueryStress からの結果は、SQL Server Profiler に対してテストされます。精度は SQL Server Profiler と同じですが、歳差運動は小数点以下 2 桁少なくなります (ただし、このテストには十分です)。

質問で述べたように、主な懸念事項はアプリケーションのパフォーマンスへの影響であり、レポートの精度とパフォーマンスは二次的な考慮事項です。すべてのテストは、テスト アプリケーションがアクティブで、いくつかの小さなアクティビティがあるテスト サーバーで行われました。

ダウンロードして SQLQueryStress に慣れた後、単純な「ReportQuery」をセットアップして、リソースを大量に消費するようにしました。15 スレッド (合計 225 クエリ) で 15 回の反復を実行するように設定されています。合計実行時間は約 28 秒で、平均反復時間は 1.49 秒です。

進行中のアプリケーション アクティビティを表す追加/削除 'ApplicationQuery' を作成しました。1 つのスレッドで 2000 回の反復を実行するように設定されています。select ステートメントを含むバージョン (31 秒実行) と、select ステートメントを含まないバージョン (28 秒実行) の 2 つのバージョンがあります。これらは、通常のピーク時のアプリケーション アクティビティを表します。

「ReportQuery」の 3 つのバージョンのそれぞれについて 10 回のテスト実行が実行されます。これは、「with(nolock)」、「with(readpast)」、および「hints なし」の間にパフォーマンス上の利点があるかどうかを識別するためです。結果は、ReportQuery が平均 1.5 秒の反復時間で約 28 秒で常に実行されることに大きな違いがないことを示しています。

大きな外れ値はないので、次のテストでは 5 回のテスト実行に落とすことにしました。

select ステートメントを使用した ApplicationQuery の 5 回のテスト実行。「ReportQuery」の 3 つのバージョンのそれぞれも実行されています。合計 15 回のテストのそれぞれで、ApplicationQuery が手動で開始され、その直後に ReportQuery が手動で開始されます。このシナリオは、リソースを大量に消費するレポート クエリが、リソースに対するアプリケーションの進行中のアクティビティに苦労していることを表しています。

テストの実行を繰り返しましたが、今回は select ステートメントなしで ApplicationQuery を使用しました。

結果: いずれの場合も、ReportQuery の実行中に、ApplicationQuery はほとんど前進しない状態に調整されました。

ReportQuery は、データベースに対して複数の ApplicationQuery を使用してリソースに苦労しても、パフォーマンスが大幅に低下することはありませんでした。

ApplicationQuery は ReportQuery と並行してクエリを実行できましたが、リソースの競合中は進行が非常に遅くなりました。本質的に、2000 のアプリケーションの追加/削除クエリを実行する合計時間は、ReportQuery によって使用される時間だけ延長されました。

どちらがより正確かという最初の質問は、無意味になります。ヒント NOLOCK または READPAST を使用しても使用しなくても、レポートまたはアプリケーションのパフォーマンスに本質的な違いはありません。したがって、ビジーなデータベースではどちらも使用せず、可能な限り最高の精度を得てください。

「ReportQuery」</p>

select 
ID
, [TABLE_NAME]
, NUMBER
, FIELD
, OLD_VALUE
, NEW_VALUE
, SYSMODUSER
, SYSMODTIME
, SYSMODCOUNT

from dbo.UPMCINCIDENTMGMTAUDITRECORDSM1 

where Number like '%'
or NUMBER like '2010-01-01'

'ApplicationQuery' (Select ステートメントを使用)

select * 

from dbo.UPMCINCIDENTMGMTAUDITRECORDSM1 
where FIELD = 'JJTestingPerformance'


insert into dbo.UPMCINCIDENTMGMTAUDITRECORDSM1 (ID
, [TABLE_NAME]
, NUMBER
, FIELD
, OLD_VALUE
, NEW_VALUE
)

values ('Test+Time'
, 'none'
, 'tst01'
, 'JJTestingPerformance'
, 'No Value'
, 'Test'
)

delete from dbo.UPMCINCIDENTMGMTAUDITRECORDSM1

where FIELD = 'JJTestingPerformance'

'ApplicationQuery' (Select ステートメントなし)

insert into dbo.UPMCINCIDENTMGMTAUDITRECORDSM1 (ID
, [TABLE_NAME]
, NUMBER
, FIELD
, OLD_VALUE
, NEW_VALUE
 )

values ('Test+Time'
, 'none'
, 'tst01'
, 'JJTestingPerformance'
, 'No Value'
, 'Test'
)

delete from dbo.UPMCINCIDENTMGMTAUDITRECORDSM1

where FIELD = 'JJTestingPerformance'

テスト結果のスクリーンショット

于 2013-04-15T13:20:03.587 に答える