Медленная пакетная/массовая вставка в SQLite

Я пытаюсь импортировать данные из файла csv в таблицу sqlite. Мои тестовые данные составляют всего около 8 МБ (50 000 строк) и занимают около 15 секунд. Однако производственные данные занимают почти 400 МБ и занимают вечность (по крайней мере, 30 минут +, я перестал ждать).

После долгих исследований я обнаружил необходимость вставки в одну транзакцию (это привело меня к 15-секундному импорту, отличный совет! :)) Так что это не проблема. (НАСКОЛЬКО МНЕ ИЗВЕСТНО)

Я также использую «ExecuteNonQuery() в параметризованном операторе INSERT» согласно этому сообщению Роберта Симпсона. - и многочисленные варианты.

Я просто использовал TextReader.ReadLine() и String.Split('\t'), затем я где-то прочитал о том, что ReadLine() работает медленно из-за количества операций чтения с диска, поэтому я изучил чтение буферизованного потока и наткнулся на эта программа чтения csv. Но по-прежнему никаких заметных изменений в производительности.

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

Вот обычная версия моего кода. Заранее спасибо, это сводит меня с ума! Я собираюсь попробовать импортировать в набор данных и вставить это?....

using (TextReader tr = File.OpenText(cFile))
{                       
    using (SQLiteConnection cnn = new SQLiteConnection(connectionString))
    {
        string line;
        string insertCommand = "INSERT INTO ImportTable VALUES (@P0,@P1,@P2,@P3,@P4)";

        cnn.Open();
        SQLiteCommand cmd = new SQLiteCommand("begin", cnn);
        cmd.ExecuteNonQuery();

        cmd.CommandText = insertCommand;

        while ((line = tr.ReadLine()) != null)
        {
            string[] items = line.Split('\t');

            cmd.Parameters.AddWithValue("@P0", items[0]);
            cmd.Parameters.AddWithValue("@P1", items[1]);
            cmd.Parameters.AddWithValue("@P2", items[2]);
            cmd.Parameters.AddWithValue("@P3", items[3]);
            cmd.Parameters.AddWithValue("@P4", items[4]);
            cmd.ExecuteNonQuery();
        }
        cmd.CommandText = "end";
        cmd.ExecuteNonQuery(); 
    }              
}

Обновление: я только что попытался использовать вставку с параметрами (просто жестко закодировал некоторые значения), менее 5 секунд... все еще не так быстро, как статьи, которые я видел...

Кроме того, я использую Core2 Duo (3Ghz) с 2G Ram, XP.


person Matt C    schedule 10.03.2011    source источник
comment
Вы уверены, что команды begin и end работают? Заметите ли вы изменение времени выполнения, если их убрать?   -  person Daniel Hilgarth    schedule 10.03.2011
comment
Спасибо. Да вроде работают. Я пробую это сейчас без них, и до сих пор у меня ушло не менее 10 минут (было 15 секунд) ... Я также пробовал способ transaction = connection.BeginTransaction()/.transaction.commit (нормальная производительность, как указано выше).   -  person Matt C    schedule 10.03.2011
comment
в порядке. Просто хотел, чтобы это подтвердилось. Потому что я собирался предложить использовать Transaction или TransactionScope... Но это не решит вашу проблему, чем...   -  person Daniel Hilgarth    schedule 10.03.2011
comment
Это все еще работало после двух часов...   -  person Matt C    schedule 10.03.2011
comment
Только что нашел еще несколько вещей, которые вы могли бы попробовать: blog.quibb. org/2010/08/fast-bulk-inserts-into-sqlite   -  person grimmig    schedule 10.03.2011


Ответы (1)


Так что я думаю, что решил проблему или, по крайней мере, нашел решение.

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

Я создал свою базу данных и таблицы в подключаемом модуле SQLite Manager для Firefox.

Итак, я воссоздал все из командной оболочки, и БУМ! Мой импорт сократился до нескольких секунд!

Я знал, что проблема в том, что он не может обрабатывать 64-битные целые числа (но использовал только типы данных TEXT). Возможно, есть проблема с SQLite Manager, использующим другой движок SQLite для версии .Net? Я не знаю.

Следующим моим шагом может быть создание таблиц db + из моего приложения, вместо их предварительной подготовки... Но сейчас я вполне доволен производительностью, так что это не приоритет.

person Matt C    schedule 12.03.2011