Mejore el rendimiento de inserciones masivas SQLite utilizando Dapper ORM

.net dapper sqlite

Pregunta

Estoy trabajando en una aplicación de escritorio que usa SQLite para insertar a granel decenas de miles de filas en una base de datos SQLite. Me gustaría ayudar a optimizar el rendimiento de la inserción masiva. Actualmente, se requieren hasta 50 segundos para insertar datos de 60 megas en la base de datos.

  • ¿Qué parámetros de cadena de conexión podría usar para mejorar el rendimiento? ¿Debo cambiar el tamaño del búfer? ¿Es esto posible a través de un parámetro de cadena de conexión? ¿Hay algún otro parámetro de cadena de conexión para mejorar el rendimiento? Mi cadena de conexión actual es:

    Fuente de datos = Batch.db; Version = 3; Pooling = True; Tamaño máximo de pool = 10; Sincrónico = desactivado; FailIfMissing = True; Modo Journal = Desactivado;

  • Estoy usando Dapper ORM. (creado por los chicos de StackOverflow) ¿Existe alguna forma más rápida de insertar a granel en Sqlite, en .net?

  • System.Data.Sqlite se está utilizando para insertar en SQLite. ¿Qué tal obtener una versión compilada especial de sqlite que mejore el rendimiento? ¿Una versión de SQLite es mejor que otra? Actualmente usa System.Data.SQLite desde http://sqlite.phxsoftware.com

  • Actualmente, estoy envolviendo insertos dentro de una transacción para hacerlos más rápidos (esto hizo una buena mejora).

  • Estoy insertando en una tabla a la vez en 17 tablas. ¿Podría paralelizar esto en diferentes hilos y hacerlo más rápido?

Actuación actual. Es esto típico? ¿Puedo hacerlo mejor?

  • 55,000 filas en la tabla con 19 columnas: 2,25 segundos para insertar (24k insertos / seg)
  • 10.000 filas en la tabla con 63 columnas: 2.74 segundos para insertar (3.7k / seg)

Me gusta SQLite, pero me gustaría hacerlo un poco más rápido. Actualmente, guardar mis objetos en un archivo XML utilizando la serialización XML es más rápido que guardarlos en una base de datos SQLite, por lo que mi jefe pregunta: ¿por qué cambiar a SQLite? ¿O debería estar usando MongoDB, o alguna otra base de datos de objetos?

Respuesta aceptada

Así que finalmente encontré el truco para inserciones masivas de alto rendimiento en SQLite usando .NET. ¡Este truco mejoró el rendimiento de la inserción en un factor de 4.1! Mi tiempo total de ahorro fue de 27 segundos a 6.6 segundos. ¡Guauu!

Este artículo explica la forma más rápida de hacer inserciones masivas en SQLite . La clave es reutilizar los mismos objetos de parámetro pero para cada registro para insertar, asignando un valor diferente. El tiempo que toma .NET para construir todos esos objetos DbParameter realmente se suma. Por ejemplo, con 100k filas y 30 columnas = 3 millones de objetos de parámetros que deben crearse. En cambio, crear y reutilizar solo 30 objetos de parámetros es mucho más rápido.

Nuevo rendimiento:

  • 55,000 filas (19 columnas) en .53 segundos = 100k insertos / segundo

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

Termina que no pude usar Dapper para insertarlo en mis tablas grandes. (Para mis mesas pequeñas, todavía uso Dapper).

Tenga en cuenta, algunas otras cosas que encontré:

  • Intenté usar varios hilos para insertar datos en la misma base de datos, esto no mejoró. (no hizo la diferencia)

  • Actualizado de System.Data.Sqlite 1.0.69 a 1.0.79. (No hizo una diferencia en el rendimiento que pude ver)

  • No estoy asignando un Type al DbParameter, no parece hacer una diferencia de rendimiento de ninguna manera.

  • Para las lecturas, no pude mejorar el rendimiento de Dapper.


Respuesta popular

Actualmente, estoy envolviendo insertos dentro de una transacción para hacerlos más rápidos (esto hizo una buena mejora).

La mayor ganancia que he visto en la velocidad de inserción masiva fue romper las inserciones en trozos más pequeños. Qué tan pequeño de un trozo varía por plataforma / esquema / etc., estoy seguro. Creo que durante mis pruebas fue cerca de 1000 o así.



Licencia bajo: CC-BY-SA with attribution
No afiliado con Stack Overflow
¿Es esto KB legal? Sí, aprende por qué
Licencia bajo: CC-BY-SA with attribution
No afiliado con Stack Overflow
¿Es esto KB legal? Sí, aprende por qué