55 votes

SQLite Insert très lent ?

Je me suis récemment renseigné sur SQLite et j'ai pensé que j'allais essayer. Mais quand je vois l'insertion d'un enregistrement, tout va bien. Mais quand j'en ai inséré 100, cela a pris 5 secondes et plus la taille de l'enregistrement augmente, plus le temps augmente. Qu'est-ce qui peut bien se passer ? Je suis un wrapper SQLite. (system.data.SQlite)

exemple de code

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

//---INSIDE LOOP

 SQLiteCommand sqlComm = new SQLiteCommand(sqlQuery, dbcon);

 nRowUpdatedCount = sqlComm.ExecuteNonQuery(); 

//---END LOOP

dbcon.close();

76voto

jojaba Points 3915

Enveloppe BEGIN \ END autour de vos insertions en masse. Sqlite est optimisé pour les transactions.

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

31voto

Jared Harley Points 4729

Essayez d'emballer tous vos encarts (c'est-à-dire un encart en vrac) dans un seul transaction :

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

Par défaut, SQLite englobe toutes les insertions dans une transaction. ce qui ralentit le processus :

INSERT est vraiment lent - je ne peux effectuer que quelques dizaines d'INSERT par seconde.

En fait, SQLite peut facilement effectuer 50 000 instructions INSERT ou plus par seconde sur un ordinateur de bureau moyen. Mais il ne fera que quelques dizaines de transactions par seconde.

La vitesse des transactions est limitée par la vitesse du disque dur car (par défaut) SQLite attend que les données soient réellement stockées en toute sécurité sur la surface du disque avant que la transaction ne soit terminée. De cette façon, si vous perdez soudainement de l'énergie ou si votre système d'exploitation se plante, vos données sont toujours en sécurité. Pour plus de détails, lisez ce qui concerne le commit atomique dans SQLite

Par défaut, chaque instruction INSERT constitue sa propre transaction. Mais si vous entourez plusieurs instructions INSERT de BEGIN...COMMIT, toutes les insertions sont regroupées en une seule transaction. Le temps nécessaire pour valider la transaction est amorti sur toutes les instructions d'insertion incluses, ce qui réduit considérablement le temps par instruction d'insertion.

8voto

Scott Points 51

Voir "Optimisation des requêtes SQL" dans le fichier d'aide ADO.NET SQLite.NET.chm. Code de cette page :

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

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X