2012-09-24 12 views
8

Przeprowadzam kilka długotrwałych zapytań SQL w ramach modułu raportowania. Te zapytania są budowane dynamicznie w czasie wykonywania. W zależności od danych wprowadzanych przez użytkownika, mogą to być pojedyncze lub wielokrotne wyciągi, mieć jeden lub więcej parametrów i działać na jednej lub wielu tabelach baz danych - innymi słowy, ich forma nie może być łatwo przewidziana.Użyj SqlTransaction & IsolationLevel do długotrwałej operacji odczytu?

Obecnie jestem po prostu wykonując te oświadczenia na zwykłym SqlConnection, tj

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

Ponieważ te pytania (naprawdę kwerendy partii) może potrwać do wykonania, jestem zaniepokojony zamków na stołach trzyma się czyta/pisze dla innych użytkowników. Nie stanowi to problemu, jeśli dane dotyczące tych raportów zmieniają się podczas realizacji partii; kwerendy raportu nigdy nie powinny mieć pierwszeństwa przed innymi operacjami na tych tabelach, ani nie powinny je blokować.

Dla większości operacji długotrwałych/Multi-oświadczenie, które wymagają modyfikacji danych, chciałbym wykorzystywać transakcje. Różnica polega na tym, że te kwerendy raportu nie modyfikują żadnych danych. Czy poprawne jest zawijanie tych zapytań raportu w celu sprawdzenia ich poziomu izolacji?

tj:

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

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

     tr.Commit(); 
    } 
} 

Czy to osiągnąć mój pożądany efekt? Czy prawidłowe jest zatwierdzenie transakcji, mimo że żadne dane nie zostały zmodyfikowane? Czy istnieje inne podejście?

+0

Czy raporty mają być [właściwy] (http://blogs.msdn.com/b/sqlcat/archive/2007/02/01/previously-committed-rows-might- be-missed-if-nolock-hint-is-used.aspx) czy nie? –

+0

@RemusRusanu Raporty zapewniają natychmiastową migawkę danych przez długi czas; nie muszą brać pod uwagę zmian, które mogą wystąpić w trakcie transakcji. Podstawowe zapytania będą prawdopodobnie uruchamiane wielokrotnie przez użytkownika w krótkim odstępie czasu, a użytkownik nie będzie oczekiwał, że wyniki będą za każdym razem identyczne. –

+1

To jest dokładnie ten rodzaj raportów, które zostały uszkodzone (źle) przez brudne odczyty. Liczby i agregaty przeskakują losowo w górę i w dół, a dane w jednym przebiegu (raport) nie będą spójne (np. Suma debetu! = Suma kredytu). Twoi użytkownicy stracą zaufanie do raportu, ponieważ będzie on wydawał losowe dane. Czy zamiast tego rozważałeś ['SNAPSHOT'] (http://msdn.microsoft.com/en-us/library/ms345124 (v = sql.90) .aspx)? –

Odpowiedz

5

Innym rozwiązaniem może być do wydania, przed połączeniem:

SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED; 

która osiąga tę samą intencję, nie brudząc z transakcją. Możesz też użyć podpowiedzi WITH(NOLOCK) dla tabel w zapytaniu, która ma tę zaletę, że w ogóle nie zmienia połączenia.

Co ważne, należy pamiętać, że (wyjątkowo): jednak robi się zmieniło (transakcja, transakcji zakres, wyraźny SET, etc), poziom izolacji jest nie resetowania między zastosowań tego samego połączenia bazowego podczas pobierania z puli. Oznacza to, że jeśli kod zmienia poziom izolacji (bezpośrednio lub pośrednio), a następnie żaden z kodem wie co poziom izolacji nowego połączenia jest:

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 
} 

co sprawia, że ​​WITH(NOLOCK) całkiem kusząca.

+0

.... zbyt krótkie wyjaśnienie swoich sugestii. – ulrichb

+1

Wow, dzięki za ostrzeżenie o ustawieniu poziomu izolacji ... które może być niebezpieczne. –

+0

Ustalając poziom izolacji za pomocą BeginTransaction, czy unikniemy problemu "poziom izolacji nie został zresetowany między połączeniami", o którym wspomniałeś? Jeśli tak, czy jest jakaś wada w korzystaniu z transakcji? – digEmAll

1

zgadzam się z Markiem, ale alternatywnie można użyć kwerendy wskazówkę NOLOCK na stołach dotkniętych. Dałoby to możliwość kontrolowania go na stole według poziomu tabeli.

Problem z uruchomieniem jakiekolwiek pytania bez podejmowania wspólnych zamków jest to, że zostawić sobie otwarte na „non-deterministyczne” wyniki oraz decyzje biznesowe nie powinny być dokonywane na podstawie tych danych.

Lepszym rozwiązaniem może być zbadanie zarówno zdjęciu lub poziomy izolacji READ_COMMITED_SNAPSHOT. Zapewniają one ochronę przed anomolami transakcyjnymi bez blokowania. Kompromisem jest to, że zwiększają IO względem TempDB. Każdy z tych poziomów można zastosować albo do sesji, jak sugerował Marc, albo do tabeli, tak jak sugerowałem.

Nadzieja to pomaga

Powiązane problemy