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 53

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 или более инструкций вставки в секунду на среднем настольном компьютере. Но это будет только делать несколько десятков транзакций в секунду.

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

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

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

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

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

PRAGMA journal_mode = WAL
PRAGMA synchronous = NORMAL

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

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

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();
}