2012-09-24 7 views
8

私は、レポートモジュールの一部として、いくつかの長期実行SQLクエリを実行しています。これらのクエリは、実行時に動的に構築されます。ユーザーの入力に応じて、単一または複数のステートメントで、1つ以上のパラメーターを持ち、1つ以上のデータベース表で操作できます。つまり、その形式を容易に予測できません。長時間の読み取り操作にはSqlTransactionとIsolationLevelを使用しますか?

現在、私はちょうどこれらのクエリは、(実際にバッチを照会)を実行するためにしばらく時間がかかることがあるので、私は読み取り持ちこたえ表に対するロックが心配ですすなわち

using (SqlConnection cn = new SqlConnection(ConnectionString)) { 
    cn.Open(); 
    // command 1 
    // command 2 
    // ... 
    // command N 
} 

、通常のSqlConnection上でこれらのステートメントを実行しています/他のユーザーの書き込み。バッチの実行中にこれらのレポートのデータが変更されても問題はありません。レポートクエリは、それらのテーブルの他の操作より優先されるべきではなく、それらをロックする必要もありません。

データの変更を伴う、ほとんどの長期実行/複数ステートメント操作では、トランザクションを使用します。違いは、これらのレポートクエリがデータを変更していないことです。分離レベルを制御するために、これらのレポートクエリをSqlTransactionにラップするのは正しいでしょうか?

すなわち:

using (SqlConnection cn = new SqlConnection(ConnectionString)) { 
    cn.Open(); 

    using (SqlTransaction tr = cn.BeginTransaction(IsolationLevel.ReadUncommitted)) { 
     // command 1 
     // command 2 
     // ... 
     // command N 

     tr.Commit(); 
    } 
} 

は、この私の望ましい結果を達成しますか?データが変更されていないのにトランザクションをコミットするのは正しいですか?別の方法がありますか?

SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED; 

トランザクションいじりせずに、同じ意図を実現:

+0

レポートはhttp://blogs.msdn.com/b/sqlcat/archive/2007/02/01/previously-committed-rows-might-([正しい]である必要はありますができますbe-missed-if-nolock-hint-is-used.aspx)そうでないか? –

+0

@RemusRusanuレポートは、長期間のデータの瞬時スナップショットを提供します。トランザクション中に発生する可能性がある変更を考慮する必要はありません。基礎となるクエリは、ユーザによって短い連続で複数回実行される可能性が高く、ユーザは結果が毎回同じであるとは期待しない。 –

+1

これは不正な読み込みによって(ひどく)影響を受けるレポートとまったく同じです。カウントと集計はランダムに上下にジャンプし、1回の実行(レポート)内のデータは一貫性がありません(例:合計デビット!=合計クレジット)。ユーザーはランダムなデータを生成するように見えるので、レポートに対する信頼感が失われます。代わりに['SNAPSHOT'](http://msdn.microsoft.com/en-us/library/ms345124(v = sql.90).aspx)を考えましたか? –

答えて

5

別のアプローチは、接続に対して、発行するかもしれません。または、クエリ内のテーブルに対してWITH(NOLOCK)ヒントを使用することができます。これにより、接続をまったく変更しないという利点があります。重要なことに

、(異常)ことに注意してください。しかしながらそれは(トランザクション、トランザクションスコープ、明示SET等)変更、分離レベルは、同じ基本接続の使用の間ないリセットされますそれをプールからフェッチするとき。

WITH(NOLOCK)は非常に魅力的になり
using(var conn = new SqlConnection(connectionString)) { 
    conn.Open(); 
    // isolation level here could be **ANYTHING**; it could be the default 
    // if it is a brand new connection, or could be whatever the last 
    // connection was when it finished 
} 

:これはあなたのコードは、分離レベルを(直接または間接的に)変更した場合、その後、あなたのコードのどれも新しい接続の分離レベルが何であるかを知らないことを意味します。

+0

....あなたの提案があまりにも短い説明。 – ulrichb

+1

ワウ、隔離レベルを設定することについての警告のために感謝します...危険である可能性があります。 –

+0

BeginTransactionを使用して分離レベルを設定することで、言及した「分離レベルが接続間でリセットされない」問題を回避できますか?もしそうなら、トランザクションを使用する際に欠点はありますか? – digEmAll

1

私はMarcに同意しますが、影響を受けるテーブルでNOLOCKクエリヒントを使用することもできます。これは、あなたがテーブルレベルでテーブル上でそれを制御する能力を与えるでしょう。

共有ロックを使用せずにクエリを実行すると、「非決定論的」な結果が出る可能性があり、このデータに対してビジネス上の決定を下すべきではありません。

より良いアプローチは、SNAPSHOTまたはREAD_COMMITED_SNAPSHOT分離レベルのいずれかを調べることです。これらは、ロックを取ることなくトランザクションの無差別に対する保護を提供します。トレードオフは、TempDBに対してIOを増やすことです。これらのレベルは、Marcが提案したセッションまたは私が提案したテーブルに適用できます。

希望これは

関連する問題