2011-02-01 3 views
5

У меня есть следующие (упрощенно) код, который я хотел бы, чтобы оптимизировать скорость:C# Оптимизация: Вставка 200 миллионов строк в базе данных

long inputLen = 50000000; // 50 million 
DataTable dataTable = new DataTable(); 
DataRow dataRow; 
object[] objectRow; 
while (inputLen--) 
{ 
    objectRow[0] = ... 
    objectRow[1] = ... 
    objectRow[2] = ... 

    // Generate output for this input 
    output = ... 

    for (int i = 0; i < outputLen; i++) // outputLen can range from 1 to 20,000 
    { 
     objectRow[3] = output[i]; 
     dataRow = dataTable.NewRow(); 
     dataRow.ItemArray = objectRow; 
     dataTable.Rows.Add(dataRow); 
    } 
} 

// Bulk copy 
SqlBulkCopy bulkTask = new SqlBulkCopy(connection, SqlBulkCopyOptions.TableLock, null); 
bulkTask.DestinationTableName = "newTable"; 
bulkTask.BatchSize = dataTable.Rows.Count; 
bulkTask.WriteToServer(dataTable); 
bulkTask.Close(); 

Я уже использую SqlBulkCopy в попытке ускорить процесс , но кажется, что присвоение значений самому DataTable оказывается медленным.

Я не знаю, как работают DataTables, поэтому мне интересно, создаю ли лишние накладные расходы, сначала создав многоразовый массив, а затем назначив его DataRow, а затем добавив DataRow в DataTable? Или же использовать DataTable не оптимально в первую очередь? Вход поступает из базы данных.

Меня не волнует LOC, просто скорость. Может ли кто-нибудь дать совет по этому поводу?

+0

Для примера реализации рассмотрим 'SimpleDataReader' [здесь] (https://groups.google.com/group/microsoft.public.dotnet.languages.csharp/msg/b1d70b504cdee2ad?hl=ru) –

ответ

13

Для такой большой таблицы, вы должны использовать метод

public void WriteToServer(IDataReader reader) 

.

Это может означать, что вы должны реализовать свой «поддельный» интерфейс IDataReader с вашим кодом (если вы не получите данные из существующего IDataReader), но таким образом вы получите «потоковое» сообщение, от конца до конца, и избежит цикла 200 миллионов.

+1

Угадайте, что вы избили меня до него :) –

+0

Означает ли это, что SQLBulkCopy может эффективно писать базу данных **, поскольку ** строятся строки ? Вход поступает из той же базы данных, но для каждой строки я потенциально создаю 20000 новых. –

+0

@ Box9 да, именно это –

0

Вы не должны создавать целые данные в памяти. Используйте этот overload WrtieToServer, который принимает массив DataRow. Просто разделите куски вашими данными.

+0

Isn ' t этот метод все еще строит его в памяти? И кроме того, если у меня не хватает памяти, не строит ли это в памяти быстрее всего? –

+0

, если вы создадите только 1k строк за один раз вместо 200m, менеджеру памяти было бы намного легче хранить такой объем данных. кроме того, ваш почти наверняка будет заменен на 200 м записей в памяти за один раз – gor

4

Вместо того, чтобы хранить огромную таблицу данных в памяти, я бы предложил реализовать IDataReader, который обслуживает данные в виде массовой копии. Это уменьшит необходимость держать все в памяти заранее и, таким образом, будет способствовать повышению производительности.

Смежные вопросы