Melhore o desempenho de inserções em massa SQLite usando o Dapper Orm
Pergunta
Eu estou trabalhando em um aplicativo de desktop que usa o SQLite para inserir a granel de dezenas de milhares de linhas em um banco de dados SQLite. Eu gostaria de ajudar a otimizar o desempenho da inserção em massa. Atualmente, leva 50 segundos para inserir 60 megs no valor de dados no banco de dados.
-
Quais paramentes de string de conexão eu poderia usar para melhorar atuação? Devo alterar o tamanho do buffer? É isso possível através de um Parâmetro de cadeia de conexão? Existem outra cadeia de conexão parâmetros para melhorar o desempenho? Minha cadeia de conexão atual é:
.
fonte de dados= batch.db; versão= 3; pooling= true; pool max Tamanho= 10; síncrono= desligado; failifmissing= true; modo de diário= desligado;
Eu estou usando o Dapper Orm. (Construído pelos caras do Stackoverflow) Existe uma maneira mais rápida de inserir em massa em SQLite, no .NET?
system.data.sqlite está sendo usado para inserir no SQLite. Que tal obter uma versão especial compilada do SQLite que melhora atuação? É uma versão do SQLite melhor que outra? Atualmente usando system.data.sqlite de http://sqlite.phxsoftware.com
Atualmente, estou envolvendo inserções dentro de uma transação para torná-los mais rápido (isso fez uma boa melhoria).
Estou inserindo em uma tabela de cada vez em 17 tabelas. Eu poderia paralelizar isso em tópicos diferentes e tornar isso mais rápido?
desempenho atual. Isso é típico? Posso fazer melhor?
- 55.000 linhas na tabela com 19 colunas: 2,25 seg para inserir (24k insertos / seg)
- 10.000 linhas na tabela com 63 colunas: 2,74 seg para inserir (3.7k / seg)
Eu gosto de sqlite, mas eu adoraria torná-lo um pouco mais rápido. Atualmente, salvando meus objetos para um arquivo XML usando a serialização XML é mais rápido do que salvar para um banco de dados SQLite, então meu chefe está perguntando: Por que mudar para SQLite? Ou devo estar usando o MongoDB, ou algum outro banco de dados de objeto?
Solução
Então eu finalmente encontrei o truque para inserções em massa de alto desempenho no SQLite usando .NET. Este truque melhorou o desempenho de inserção por um fator de 4.1! Meu tempo total de economias passou de 27 segundos para 6,6 segundos. Uau!
Este artigo explica o mais rápido maneira de fazer Bulk insere em sqlite . A chave é reutilizar os mesmos objetos de parâmetros, mas para cada registro para inserir, atribuindo um valor diferente. O tempo que .NET leva construindo todos esses objetos de dbparameter realmente adiciona. Por exemplo, com 100k linhas e 30 colunas= 3 milhões de objetos de parâmetros que devem ser criados. Em vez disso, criar e reutilizar apenas 30 objetos de parâmetros é muito mais rápido.
novo desempenho:
-
55.000 linhas (19 colunas) em .53 segundos= inserções 100k / 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(); }
Isso acaba que eu não poderia usar Dapper para inserir em minhas tabelas grandes. (Para minhas pequenas mesas, ainda uso Dapper).
Note, algumas outras coisas que eu encontrei:
-
Eu tentei usar vários threads para inserir dados no mesmo banco de dados, isso não fez nenhuma melhoria. (não fez a diferença)
-
Atualizado de System.data.sqlite 1.0.69 a 1.0.79. (não fez diferença no desempenho que eu podia ver)
-
Eu não estou atribuindo um tipo ao dbparameter, não parece fazer uma diferença de desempenho de qualquer maneira.
-
para leituras, não pude melhorar o desempenho da Dapper.
-
Outras dicas
.Atualmente, estou envolvendo inserções dentro de uma transação para fazê-los mais rápido (isso fez uma boa melhoria).
O maior ganho que já vi na velocidade de inserção em massa era quebrar inserções em pedaços menores.Quão pequeno de um pedaço varia por plataforma / esquema / etc, tenho certeza.Eu acredito que durante meus testes foi quase 1000 ou mais.