2014-12-09 43 views
8

Mamy już uruchomić system, który obsługuje wszystkie ciągi połączeniowy (DB2, oracle, MSServer).Milion wkładki: SqlBulkCopy Timeout

Obecnie używamy ExecuteNonQuery() do wykonania niektórych przekładek.

Chcemy poprawić wydajność, używając SqlBulkCopy() zamiast ExecuteNonQuery(). Mamy kilku klientów, którzy mają ponad 50 milionów rekordów.

Nie chcemy używać SSIS, ponieważ nasz system obsługuje wiele baz danych.

Utworzono przykładowy projekt, aby przetestować wydajność SqlBulkCopy(). Stworzyłem prostą funkcję odczytu i wstawić do MSServer

Oto mała funkcja:

public void insertIntoSQLServer() 
{ 
    using (SqlConnection SourceConnection = new SqlConnection(_sourceConnectionString)) 
    { 
     //Open the connection to get the data from the source table 
     SourceConnection.Open(); 
     using (SqlCommand command = new SqlCommand("select * from " + _sourceSchemaName + "." + _sourceTableName + ";", SourceConnection)) 
     { 
      //Read from the source table 
      command.CommandTimeout = 2400; 
      SqlDataReader reader = command.ExecuteReader(); 

      using (SqlConnection DestinationConnection = new SqlConnection(_destinationConnectionString)) 
      { 
       DestinationConnection.Open(); 
       //Clean the destination table 
       new SqlCommand("delete from " + _destinationSchemaName + "." + _destinationTableName + ";", DestinationConnection).ExecuteNonQuery(); 

       using (SqlBulkCopy bc = new SqlBulkCopy(DestinationConnection)) 
       { 
        bc.DestinationTableName = string.Format("[{0}].[{1}]", _destinationSchemaName, _destinationTableName); 
        bc.NotifyAfter = 10000; 
        //bc.SqlRowsCopied += bc_SqlRowsCopied; 
        bc.WriteToServer(reader); 
       } 
      } 
     } 
    } 
} 

Kiedy mam mniej niż 200 000 w moim dummyTable kopia większość pracuje bez zarzutu. Ale gdy jest to ponad 200 000 rekordów, mam następujące błędy:

  • Próba wywołania masowego kopiowania obiektu, który ma oczekującą operację.

lub

  • Operacja oczekiwania limit czasu (na IDataReader)

że zwiększyła CommandTimeout dla czytelnika. Wygląda na to, że rozwiązał problem limitu czasu związanego z IDataReader.

Czy robię coś nie tak w kodzie?

+1

Nigdy nie SqlBulkCopy do tabeli docelowej. To coś poważnie złamało kod blokujący. Zwłaszcza przy użyciu wielowątkowości. Utwórz tabelę tymczasową, wstaw do niej, a następnie skopiuj do tabeli docelowej. – TomTom

+0

Nie używam wielowątkowości. Zawsze wkładam do pustego stołu. – billybob

+2

Dlaczego w ogóle sqlbulkcopy? Poważnie. Tabele na tej samej bazie danych - po prostu powiedz serwerowi, aby skopiował dane, zamiast pobierać je do programu, aby je przesłać. Wybierz prawo do tabeli docelowej za pomocą jednej instrukcji. – TomTom

Odpowiedz

9

można spróbować dodanie poniższych przed wywołaniem WriteToServer ...

bc.BatchSize = 10000; 
bc.BulkCopyTimeout = 0; 

nie wiem co domyślna wielkość partii lub limit czasu jest, ale podejrzewam, że to może być problem. Nadzieję, że pomaga

Możesz także spróbować grać z różnymi rozmiarami partii, aby uzyskać optymalną wydajność.

0

można spróbować to

bc.BatchSize = 100000; // Ile wierszy chcesz wstawić naraz.

bc.BulkCopyTimeout = 60; // Czas w sekundach, Jeśli chcesz nieskończony czas oczekiwania, przypisz 0.

Mam nadzieję, że to ci pomoże, a także inni programiści.