SQLite Insert bardzo wolny?

Ostatnio czytałem o SQLite i pomyślałem, że spróbuję. Po włożeniu jednego rekordu działa dobrze. Ale kiedy wstawiam sto, zajmuje to pięć sekund, a wraz ze wzrostem liczby rekordów, tak samo czas. Co może być nie tak? Używam wrappera 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();
Author: mergenchik, 2010-10-04

4 answers

Wrap BEGIN \ END Oświadczenia wokół wkładek luzem. Sqlite jest zoptymalizowany pod kątem transakcji.

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();
 71
Author: tidwall,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-10-04 00:07:17

Spróbuj zawinąć wszystkie wkładki (aka, wkładka zbiorcza) w jedną transakcję :

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

Domyślnie, SQLite zawija wszystkie wstawki w transakcji , co spowalnia proces:

INSERT jest bardzo powolny - mogę zrobić tylko kilkadziesiąt wstawek na sekundę

W rzeczywistości SQLite z łatwością wykona 50 000 lub więcej poleceń wstawiania na sekundę na przeciętnym komputerze stacjonarnym. Ale zrobi tylko kilkadziesiąt transakcji na sekundę.

Prędkość transakcji jest ograniczona przez prędkość dysku, ponieważ (domyślnie) SQLite faktycznie czeka, aż DANE naprawdę są bezpiecznie przechowywane na powierzchni dysku, zanim transakcja zostanie zakończona. W ten sposób, jeśli nagle stracisz zasilanie lub system operacyjny ulegnie awarii, Twoje dane będą nadal bezpieczne. Aby uzyskać więcej informacji, przeczytaj o Atomic commit w SQLite..

Domyślnie każda instrukcja INSERT jest własną transakcją. Ale jeśli otaczasz wiele poleceń INSERT za pomocą BEGIN...COMMIT wtedy wszystkie wstawki są pogrupowane w jedną transakcję. Czas potrzebny na zatwierdzenie transakcji jest amortyzowany w stosunku do wszystkich załączonych oświadczeń insert, a więc czas na oświadczenie insert jest znacznie skrócony.

 30
Author: Jared Harley,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-10-04 00:21:17

Czytałem wszędzie, że tworzenie transakcji jest rozwiązaniem do spowolnienia zapisu SQLite, ale przepisanie kodu i owinięcie wszystkich zapisów SQLite w transakcje może być długie i bolesne.

Znalazłem znacznie prostszą, bezpieczną i bardzo wydajną metodę: włączam (domyślnie wyłączoną) optymalizację SQLite 3.7.0: Write-Ahead-Log (WAL) . Dokumentacja mówi, że działa we wszystkich systemach unix (tj. Linux i OSX) i Windows.

Jak ? Wystarczy uruchomić następujące polecenia po inicjalizacja połączenia SQLite:
PRAGMA journal_mode = WAL
PRAGMA synchronous = NORMAL

Mój kod działa teraz ~600% szybciej : mój zestaw testów działa teraz w 38 sekund zamiast 4 minut:)

 24
Author: david_p,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-12-04 09:16:58

Patrz "Optymalizacja zapytań SQL" w ADO.NET plik pomocy SQLite.NET. ChM. Code z tej strony:

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();
}
 8
Author: Scott,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-06-16 02:09:28