Повысить производительность объемных вставок SQLite с использованием Dapper ORM

Я работаю над настольным приложением, которое использует SQLite для массового ввода десятков тысяч строк в базу данных SQLite. Я хотел бы помочь оптимизировать производительность объемной вставки. В настоящее время занимает до 50 секунд, чтобы вставить в базу данных 60 мегабайт.

  • какие параметры строки подключения можно использовать для улучшения представление? Должен ли я изменить размер буфера? Возможно ли это с помощью параметр строки подключения? Есть ли другая строка подключения параметры для повышения производительности? Моя текущая строка подключения:

    Источник данных = Batch.db; Версия = 3; Пул = Истина; Макс. пул    Размер = 10; Синхронный = выкл. FailIfMissing = True; Режим журнала = Выкл.

  • Я использую Dapper ORM. (созданный ребятами из StackOverflow) Есть ли более быстрый способ для массовой вставки в Sqlite, в .net?

  • System.Data.Sqlite используется для вставки в SQLite. Как получить специальную скомпилированную версию sqlite, которая улучшает представление? Является ли одна версия SQLite лучше другой? В данный момент используя System.Data.SQLite от http://sqlite.phxsoftware.com

  • В настоящее время я переношу вставки внутри транзакции, чтобы сделать их быстрее (это сделало хорошее улучшение).

  • Я вставляю в одну таблицу за один раз в 17 таблиц. Могу ли я распараллелить это на разных потоках и сделать это быстрее?

Текущая производительность. Это типично? Могу ли я лучше?

  • 55 000 строк в таблицу с 19 столбцами: 2,25 с для вставки (24 тыс. вставки/сек)
  • 10 000 строк в таблицу с 63 столбцами: 2,74 с для вставки (3,7 тыс./сек)

Мне нравится SQLite, но я хотел бы сделать это немного быстрее. В настоящее время сохранение моих объектов в XML файле с использованием сериализации XML происходит быстрее, чем сохранение базы данных SQLite, поэтому мой босс спрашивает: зачем переключиться на SQLite? Или я должен использовать MongoDB или какую-либо другую базу данных объектов?

Ответ 1

Итак, я наконец нашел трюк для высокопроизводительных массивных вставок в SQLite, используя .NET. Этот трюк улучшил производительность вставки в 4,1 раза! Мое общее время сбережения составляло от 27 секунд до 6,6 секунды. Вау!

В этой статье объясняется самый быстрый способ делать массовые вставки в SQLite. Ключ используется для повторного использования одних и тех же объектов параметров, но для каждой вставки, назначая другое значение. Время, когда .NET берет на себя создание всех этих объектов DbParameter, действительно добавляет. Например, с 100k строк и 30 столбцов = 3 миллиона объектов параметров, которые необходимо создать. Вместо этого создание и повторное использование только 30 объектов параметров происходит намного быстрее.

Новая производительность:

  • 55 000 строк (19 столбцов) в .53 секунды = 100 тыс. вставок/сек

        internal const string PeakResultsInsert = @"INSERT INTO PeakResult values(@Id,@PeakID,@QuanPeakID,@ISTDRetentionTimeDiff)";
    
                var command = cnn.CreateCommand();
                command.CommandText = BatchConstants.PeakResultsInsert;
    
                string[] parameterNames = new[]
                                     {
                                       "@Id",
                                       "@PeakID",
                                       "@QuanPeakID",
                                       "@ISTDRetentionTimeDiff"
                                      };
    
                DbParameter[] parameters = parameterNames.Select(pn =>
                {
                    DbParameter parameter = command.CreateParameter();
                    parameter.ParameterName = pn;
                    command.Parameters.Add(parameter);
                    return parameter;
                }).ToArray();
    
                foreach (var peakResult in peakResults)
                {
                    parameters[0].Value = peakResult.Id;
                    parameters[1].Value = peakResult.PeakID;
                    parameters[2].Value = peakResult.QuanPeakID;
                    parameters[3].Value = peakResult.ISTDRetentionTimeDiff;
    
                    command.ExecuteNonQuery();
                }
    

В конце концов, я не мог использовать Dapper для вставки в мои большие таблицы. (Для моих маленьких таблиц я все еще использую Dapper).

Заметьте, некоторые другие вещи, которые я нашел:

  • Я попытался использовать несколько потоков для вставки данных в одну базу данных, это не улучшилось. (не имеет значения)

  • Обновлено с System.Data.Sqlite 1.0.69 до 1.0.79. (не меняя производительность, которую я мог видеть)

  • Я не назначаю тип DbParameter, он, похоже, не имеет разницы в производительности.

  • Для чтения я не смог улучшить производительность Dapper.

Ответ 2

В настоящее время я обматываю вставки внутри транзакции, чтобы сделать их быстрее (это сделало хорошее улучшение).

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