Можно ли ускорить вставку в SQL Server при использовании инструкций INSERT INTO с ADO.net? - PullRequest
0 голосов
/ 13 марта 2012

Я смотрю, есть ли что-то, что я могу сделать, чтобы значительно ускорить вставку ADO.net, но все же делаю вставку с помощью нескольких команд INSERT INTO table values (...). Я размещаю данные из проприетарных, не запрашиваемых файлов базы данных в SQL Server. Утилита, которую я пишу, будет использоваться из скрипта.

Я понимаю, что для достижения наилучшей производительности, INSERT INTO - это неправильный путь, но я все же хотел бы знать, есть ли какой-то подход ADO.net или SQL Server, который я должен попробовать.

Я подключаюсь к SQL Server 2008 с помощью C # 2010. Я сравниваю свою производительность с неуправляемым кодом, вставляющим данные в SQL Server, используя драйвер ODBC 3.5 от Microsoft с Native Client 10.0. Разумно ли ожидать, чтобы иметь возможность соответствовать производительности ODBC?

Таблица назначения не имеет индексов или других ограничений, триггеров, это просто промежуточная таблица. Исходные данные - это набор нестандартных типов данных, которые мне нужно преобразовать в строки.

Разобравшись до соответствующей детали, мой код:

SqlCommand comm = new SqlCommand;
SqlConnection conn = new SqlConnection(connectionString);
conn.Open();
SqlTransaction insertTransaction = conn.BeginTransaction();
comm.Connection = conn;
comm.Transaction = insertTransaction;

while(buffer.ReadNext())  // fill a buffer that I use to make my query
{
    // form my insert statement and assign it
    // It looks like: INSERT INTO myTable VALUES (5,'2016-02-16',NULL,3)
    // A good fraction of the data is numeric with decimal points. A good
    // fraction is dates.  The parsing and string building,
// extravagantly inefficient as it is, is not the culprit.
    // The  INSERT INTO does not specify the column names

    comm.CommandText = myStatement;
    if (comm.ExecuteNonQuery() != 1) {throw...}
}

insertTransaction.commit;

Я пытался указать разные уровни изоляции; Я не смог указать .Snapshot (не хочу настраивать целевую базу данных, чтобы разрешить это). Ничто не имело большого значения.

Если я закомментирую comm.ExecuteNoQuery, чтобы позволить ему просто вращаться, формируя INSERT-атрибуты, он идет так быстро, как мне кажется, если бы он действительно что-то делал. Если я раскомментирую это, это займет примерно в 8 раз больше времени, чем я думаю. «Откуда берется« в 8 раз больше »? ты спрашиваешь. Что ж, я делаю аналогичную операцию (сквозная идентичная операция) с Pervasive Data Integrator (например, Data Junction). Из диагностики, когда происходит сбой Pervasive, я считаю, что программа делает вставки, используя последовательный INSERT INTO заявления, как и я. Он идет примерно в 8 раз быстрее, чем моя программа, только на очень небольшую величину медленнее, чем формирование моих операторов INSERT INTO, если я их не выполняю.

Pervasive Integrator добавляет ODBC, а драйвер ODBC настроен на использование собственного клиента Sql. И Data Integrator не является программным обеспечением .Net. Я на самом деле не пытался пройти через ODBC, я думаю, что попробую сейчас, когда это произойдет со мной, но моя цель - избавиться от ODBC, чтобы это было просто точка данных, а не решение, даже если это быстрее.

Я попытался заполнить таблицу данных с целью массовой вставки, но заполнение набора данных также заняло слишком много времени. Я предполагаю, что какой-то альтернативный способ, который использует массовую вставку, является самым быстрым способом заставить его работать, но даже если я в конечном итоге перестану использовать мой INSERT INTO подход, мне любопытно, почему это занимает намного больше времени (чем, я думаю, должно)

Операторы вставки довольно длинные, в моей таблице ~ 350 столбцов.

Ответы [ 2 ]

1 голос
/ 13 марта 2012

Вы пытались сгруппировать ваши вставляемые значения во что-то простое:

INSERT INTO myTables VALUES (5,'2016-02-16',NULL,3), (6,'2015-02-16',NULL,6), (7,'2012-02-16',NULL,6)...

Вот простая реализация, она не элегантна (а также не проверена, и я написал это в блокноте, так что есть более чем вероятные опечатки), но ...

SqlCommand comm = new SqlCommand;
SqlConnection conn = new SqlConnection(connectionString);
conn.Open();
SqlTransaction insertTransaction = conn.BeginTransaction();
comm.Connection = conn;
comm.Transaction = insertTransaction;

String baseQuery = "INSERT INTO myTable VALUES ";

List<String> values = new List<String>();

Int32 i = 0;

while(buffer.ReadNext())  // fill a buffer that I use to make my query
{
    // Build your VALUES section here
    values.Add("(5,'2016-02-16',NULL,3)");

    if (i % 100 == 0)  // Chunk these every 100
    {
        myStatement = baseQuery + String.Join(", ", values.ToArray());

        comm.CommandText = myStatement;

        if (comm.ExecuteNonQuery() != 1) {throw...}

        insertTransaction.commit;

        values = new List<String>();  // Clear out our values and start a new
    }

    i++;
}

if (values.Count > 0)  // If any are left, INSERT them
{
    myStatement = baseQuery + String.Join(", ", values.ToArray());

    comm.CommandText = myStatement;

   if (comm.ExecuteNonQuery() != 1) {throw...}

   insertTransaction.commit;
}
0 голосов
/ 13 марта 2012
  1. Данные поступают по одной строке за раз?Другими словами, у вас есть пользователи, которые вводят данные в приложение и нажимают кнопку, чтобы начать вставку?
    ИЛИ
  2. Доступны ли все данные для вставки?

Если (1.) просто сделать INSERT INTO, как вы это делали.

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

Если (2.) выполнить массовый импорт.

Существует 3 типа операций группового импорта и группового экспорта
http://msdn.microsoft.com/en-us/library/ms187042.aspx

файлы в текстовом формате?
Являются ли они столбчатыми?
Доступны ли они из файловой системы (например, C: \ pathTo \ file.ext)?
Если да, создайте файл формата bcp (распечатайте его изваша программа, стараясь включить C: \ pathTo \ file.ext).
Затем TRUNCATE промежуточной таблицы (или TRUNCATE INTO в сгенерированном выше файле формата) и вызов утилиты bcp с помощью вызова system () в заданном форматеподключение к файлу и базе данных в качестве параметров.
Это очень быстро.
Прямая загрузка bcp превзойдет все, что вы можете загрузить через ado.net.

...