SQLite вставить очень медленно?

недавно я прочитал о SQLite и подумал, что попробую. Когда я вставляю одну запись, она работает нормально. Но когда я вставляю сотню, это занимает пять секунд, и по мере увеличения количества записей увеличивается и время. Что может быть не так? Я использую оболочку SQLite (system.data.SQlite):

dbcon = new SQLiteConnection(connectionString);
dbcon.Open();

//---INSIDE LOOP

 SQLiteCommand sqlComm = new SQLiteCommand(sqlQuery, dbcon);

 nRowUpdatedCount = sqlComm.ExecuteNonQuery(); 

//---END LOOP

dbcon.close();

4 ответов


обертывание BEGIN \ END операторы вокруг ваших объемных вставок. Sqlite оптимизирован для транзакций.

dbcon = new SQLiteConnection(connectionString);
dbcon.Open();

SQLiteCommand sqlComm;
sqlComm = new SQLiteCommand("begin", dbcon);
sqlComm.ExecuteNonQuery(); 
//---INSIDE LOOP

 sqlComm = new SQLiteCommand(sqlQuery, dbcon);

 nRowUpdatedCount = sqlComm.ExecuteNonQuery(); 

//---END LOOP
sqlComm = new SQLiteCommand("end", dbcon);
sqlComm.ExecuteNonQuery(); 
dbcon.close();

попробуйте обернуть все ваши вставки (ака, массовая вставка) в один сделки:

string insertString = "INSERT INTO [TableName] ([ColumnName]) Values (@value)";

SQLiteCommand command = new SQLiteCommand();
command.Parameters.AddWithValue("@value", value);
command.CommandText = insertString;
command.Connection = dbConnection;
SQLiteTransaction transaction = dbConnection.BeginTransaction();
try
{
    //---INSIDE LOOP
    SQLiteCommand sqlComm = new SQLiteCommand(sqlQuery, dbcon);
    nRowUpdatedCount = sqlComm.ExecuteNonQuery(); 
    //---END LOOP

    transaction.Commit();
    return true;
}
catch (SQLiteException ex)
{
    transaction.Rollback();
}

по умолчанию SQLite обертывает все вставки в транзакции, что замедляет процесс:

вставка действительно медленная - я могу делать только несколько десятков вставок в секунду

на самом деле SQLite будет легко делать 50 000 или более инструкций INSERT в секунду на среднем настольном компьютере. Но этого будет достаточно. несколько десятков транзакций в секунду.

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

по умолчанию каждая инструкция INSERT является собственной транзакцией. Но если вы окружаете несколько INSERT заявления с начала...COMMIT затем все вставки группируются в одну транзакцию. Время, необходимое для фиксации транзакции, амортизируется по всем прилагаемым операторам insert, поэтому время на инструкцию insert значительно сокращается.


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

Я нашел гораздо более простой, безопасный и очень эффективный метод: я включаю (отключен по умолчанию) SQLite 3.7.0 оптимизация:Write-Ahead-Log (WAL). В документации говорится, что он работает во всех системах unix (т. е. Linux и OSX) и Windows.

Как ? Просто запустите после инициализации соединения SQLite выполните следующие команды:

PRAGMA journal_mode = WAL
PRAGMA synchronous = NORMAL

мой код теперь работает ~600% быстрее : мой тестовый набор теперь работает за 38 секунд вместо 4 минут:)


см. раздел "оптимизация SQL-запросов" в ADO.NET файл справки SQLite.Сеть.ЧМ. Код с этой страницы:

using (SQLiteTransaction mytransaction = myconnection.BeginTransaction())
{
  using (SQLiteCommand mycommand = new SQLiteCommand(myconnection))
  {
    SQLiteParameter myparam = new SQLiteParameter();
    int n;

    mycommand.CommandText = "INSERT INTO [MyTable] ([MyId]) VALUES(?)";
    mycommand.Parameters.Add(myparam);

    for (n = 0; n < 100000; n ++)
    {
      myparam.Value = n + 1;
      mycommand.ExecuteNonQuery();
    }
  }
  mytransaction.Commit();
}