Amélioration des performances des insertions en masse SQLite à l'aide de Dapper ORM

.net dapper sqlite

Question

Je travaille sur une application de bureau qui utilise SQLite pour insérer en masse des dizaines de milliers de lignes dans une base de données SQLite. Je voudrais aider à optimiser les performances de l'insert en vrac. Il faut actuellement jusqu'à 50 secondes pour insérer 60 Mo de données dans la base de données.

  • Quels paramètres de chaîne de connexion pourrais-je utiliser pour améliorer les performances? Dois-je changer la taille du tampon? Est-ce possible via un paramètre de chaîne de connexion? Existe-t-il d'autres paramètres de chaîne de connexion pour améliorer les performances? Ma chaîne de connexion actuelle est:

    Source de données = Batch.db; Version = 3; Regroupement = Vrai; Taille maximale du pool = 10; Synchrone = désactivé; FailIfMissing = True; Mode journal = Désactivé;

  • J'utilise Dapper ORM. (construit par les gars de StackOverflow) Existe-t-il un moyen plus rapide d'insérer en bloc dans Sqlite, dans .net?

  • System.Data.Sqlite est utilisé pour insérer dans SQLite. Qu'en est-il de l'obtention d'une version compilée spéciale de sqlite qui améliore les performances? Une version de SQLite est-elle meilleure qu'une autre? Actuellement, vous utilisez System.Data.SQLite depuis http://sqlite.phxsoftware.com

  • Actuellement, j'insère des insertions dans une transaction pour les rendre plus rapides (cela fait une bonne amélioration).

  • Je m'insère dans une table à la fois dans 17 tableaux. Puis-je paralléliser cela sur différents threads et rendre cela plus rapide?

Performance actuelle Est-ce typique? Puis-je faire mieux?

  • 55 000 lignes dans la table avec 19 colonnes: 2,25 sec à insérer (24 k inserts / s)
  • 10 000 lignes dans le tableau avec 63 colonnes: 2,74 secondes à insérer (3,7 ko / s)

J'aime SQLite, mais j'aimerais faire un peu plus vite. Actuellement, la sauvegarde de mes objets dans un fichier XML à l’aide de la sérialisation XML est plus rapide que l’enregistrement dans une base de données SQLite, alors mon patron demande: pourquoi passer à SQLite? Ou devrais-je utiliser MongoDB ou une autre base de données d'objets?

Réponse acceptée

J'ai donc finalement trouvé l'astuce pour les insertions en masse hautes performances dans SQLite en utilisant .NET. Cette astuce a amélioré les performances de l'insert d'un facteur de 4,1! Mon temps de gain total est passé de 27 secondes à 6,6 secondes. Hou la la!

Cet article explique le moyen le plus rapide de procéder à des insertions en masse dans SQLite . La clé est de réutiliser les mêmes objets de paramètre, mais pour chaque enregistrement à insérer, en attribuant une valeur différente. Le temps nécessaire à .NET pour construire tous ces objets DbParameter s’ajoute vraiment. Par exemple, avec 100 000 lignes et 30 colonnes = 3 millions d'objets de paramètres à créer. Au lieu de cela, créer et réutiliser seulement 30 objets de paramètre est beaucoup plus rapide.

Nouvelle performance:

  • 55 000 lignes (19 colonnes) en 0,53 seconde = 100 k inserts / seconde

        internal const string PeakResultsInsert = @"INSERT INTO PeakResult values(@Id,@PeakID,@QuanPeakID,@ISTDRetentionTimeDiff)";
    
                var command = cnn.CreateCommand();
                command.CommandText = BatchConstants.PeakResultsInsert;
    
                string[] parameterNames = new[]
                                     {
                                       "@Id",
                                       "@PeakID",
                                       "@QuanPeakID",
                                       "@ISTDRetentionTimeDiff"
                                      };
    
                DbParameter[] parameters = parameterNames.Select(pn =>
                {
                    DbParameter parameter = command.CreateParameter();
                    parameter.ParameterName = pn;
                    command.Parameters.Add(parameter);
                    return parameter;
                }).ToArray();
    
                foreach (var peakResult in peakResults)
                {
                    parameters[0].Value = peakResult.Id;
                    parameters[1].Value = peakResult.PeakID;
                    parameters[2].Value = peakResult.QuanPeakID;
                    parameters[3].Value = peakResult.ISTDRetentionTimeDiff;
    
                    command.ExecuteNonQuery();
                }
    

Il en résulte que je ne pouvais pas utiliser Dapper pour insérer dans mes grandes tables. (Pour mes petites tables, j'utilise toujours Dapper).

Notez, d'autres choses que j'ai trouvées:

  • J'ai essayé d'utiliser plusieurs threads pour insérer des données dans la même base de données, cela n'a apporté aucune amélioration. (n'a pas fait de différence)

  • Mise à niveau de System.Data.Sqlite 1.0.69 à 1.0.79. (n'a pas fait une différence de performance que j'ai pu voir)

  • Je n'attribue pas de Type à DbParameter, cela ne semble pas faire de différence de performance.

  • Pour les lectures, je ne pouvais pas améliorer les performances de Dapper.


Réponse populaire

Actuellement, j'insère des insertions dans une transaction pour les rendre plus rapides (cela fait une bonne amélioration).

Le plus grand avantage que j'ai vu dans la vitesse de l'insert en vrac était de casser les plaquettes en morceaux plus petits. Je suis certain que la taille d’un morceau varie selon la plate-forme / le schéma / etc. Je crois que lors de mes tests, il était près de 1000 ou plus.




Sous licence: CC-BY-SA with attribution
Non affilié à Stack Overflow
Est-ce KB légal? Oui, apprenez pourquoi
Sous licence: CC-BY-SA with attribution
Non affilié à Stack Overflow
Est-ce KB légal? Oui, apprenez pourquoi