2013-06-09 9 views
10

Mam ogromną listę ciągów INSERT INTO .... Obecnie biegnę im:Wysyłanie kilku poleceń SQL w pojedynczej transakcji

using (SqlConnection connection = new SqlConnection(connectionString)) 
{ 
    connection.Open(); 
    foreach (var commandString in sqlCommandList) 
    { 
     SqlCommand command = new SqlCommand(commandString, connection); 
     command.ExecuteNonQuery(); 
    } 
} 

widzę, że każdy ExecuteNonQuery() wykonuje również popełnić.

  1. Czy istnieje sposób na wstawienie wszystkich wierszy w pojedynczej transakcji (zatwierdzenie na końcu)?
  2. Powodem, dla którego chcę jednej transakcji, jest przyspieszenie procesu "wstawiania". Czy pojedyncza transakcja również przyspieszy?
+2

SQlBulkCopy http://msdn.microsoft.com/en-us/library/system.data.sqlclient.sqlbulkcopy.aspx –

+0

można użyć zakresu transakcji (patrz MSDN). – TGlatzer

+0

Możesz użyć równolegle dla każdego –

Odpowiedz

-1

Można użyć równoległego dla każdego

using (SqlConnection connection = new SqlConnection(connectionString)) 
    { 
     List<string> sqlCommandList = new List<string>(); 
     connection.Open(); 
     Parallel.ForEach(sqlCommandList, commandString => 
     { 
      SqlCommand command = new SqlCommand(commandString, connection); 
      command.ExecuteNonQuery(); 
     }); 
    } 
+3

1. parallel.foreach ładuje każdą transakcję w innym wątku (każdy wątek zakończy się zatwierdzeniem, a zatem będzie taka sama liczba zatwierdzeń). 2. Próbowałem, ale miałem problem z kolejnością wkładek. niektóre wstawki wystąpiły przed innymi i złamały moje ograniczenie klucza obcego. Ale dziękuję :-) – Jeb

27

jego zalecane użycie transakcji SQL w przypadku, gdy wykonanie wielu zapytań w jednym wątku, można mieć to tak:

SqlTransaction trans; 

    try 
    { 
     SqlConnection connection = new SqlConnection(connectionString); 
     connection.Open(); 

     trans = connection.BeginTransaction(); 

     foreach (var commandString in sqlCommandList) 
     { 
      SqlCommand command = new SqlCommand(commandString, connection,trans); 
      command.ExecuteNonQuery(); 
     } 

     trans.Commit(); 
    } 
    catch (Exception ex) //error occurred 
    { 
     trans.Rollback(); 
     //Handel error 
    } 
+0

"ExecuteNonQuery wymaga polecenia, aby mieć transakcję, gdy połączenie przypisane do polecenia jest w oczekującej transakcji lokalnej. Właściwość Transakcja polecenia nie została zainicjowana." – Fandango68

+2

@ Fernando68 >>> Polecenie SqlCommand = new SqlCommand (commandString, connection, trans); –

+0

Nie zapomnij wyrzucić obiektów SqlTransaction i SqlConnection, gdy skończysz je używać. – Sal

4

Prawdopodobnie możesz uzyskać pewną wydajność za pomocą tylko jednej transakcji i polecenia, w następujący sposób:

using (SqlConnection connection = new SqlConnection(connectionString)) 
{ 
    try 
    { 
     connection.Open(); 

     using (SqlTransaction trans = connection.BeginTransaction()) 
     { 
      using (SqlCommand command = new SqlCommand("", connection,trans)) 
      { 
      command.CommandType = System.Data.CommandType.Text; 

      foreach (var commandString in sqlCommandList) 
      { 
       command.CommandText = commandString; 
       command.ExecuteNonQuery(); 
      } 
      } 

      trans.Commit(); 
     }   
    } 
    catch (Exception ex) //error occurred 
    { 
     //Handel error 
    } 
} 
+1

Wstawiłbym wiersz 'command.ExecuteNonQuery();' w swoim bloku 'try catch', aby móc wywołać' trans.Rollback(); 'jawnie, jeśli wystąpił błąd. Tak właśnie to pokazują dokumenty MS. –

+6

@ Tony Nie trzeba wywoływać trans.rollback. Obiekt SqlTransaction zostanie wycofany w swojej metodzie Dispose(), jeśli nie został jawnie zatwierdzony (np. Jeśli zgłoszony zostanie wyjątek). Zobacz następujący wątek: [Dlaczego warto używać instrukcji using z SqlTransaction?] (Http: // stackoverflow.com/questions/1127830/why-use-a-using-statement-with-a-sqltransaction) –

+1

@Gerardo H - Jeśli jednak wywołasz go jawnie, 1) jesteś pewien, że to zrobisz powinien "Zlikwidować", przestań dzwonić wycofanie dla ciebie, 2) jest jasne dla następnego programisty, gdy nastąpi wycofanie. 3) Blok catch może również zezwalać na określone rejestrowanie błędów. Niezależnie od tego, czy sprawiają, że warto dodatkowego bałaganu będzie się różnić w zależności od przypadku. Używałem go w obie strony. – xr280xr

0

Trochę za późno, ale jeśli wstawiasz wszystkie wartości do tej samej tabeli, zakoduj wstawkę SQL jako "wstaw do wartości tablex (f1, f2, f3, ...) (@ F1, @ F2, @ F3 ...) ". Utwórz polecenie i dodaj parametry @ F1 ..., a następnie ustaw flagę Przygotuj na komendzie. Teraz podczas przeglądania listy wartości do wstawienia możesz ustawić odpowiednie parametry, a następnie wykonać polecenie ExecuteNonQuery. SQL wstępnie przetworzy ciąg poleceń, a następnie za każdym razem użyje nowych parametrów. To trochę szybciej.

Na koniec można wykonać wiele instrukcji SQL za pomocą jednego polecenia, dołączając ";" do każdej instrukcji, jeśli musisz wykonać cały ciąg. Możesz połączyć kilka z tych poleceń razem i wykonać jedno żądanie do serwera SQL, aby je wykonać.

Powiązane problemy