Pergunta

Recentemente, li sobre o SQLite e pensei que tentaria. Quando insiro um registro, ele tem um desempenho bom. Mas quando eu insiro cem, leva cinco segundos, e à medida que a contagem de registros aumenta o tempo. O que pode estar errado? Estou usando o invólucro 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();
Foi útil?

Solução

Enrolar BEGIN \ END declarações em torno de suas inserções em massa. O SQLite é otimizado para transações.

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

Outras dicas

Tente envolver todas as suas inserções (também conhecidas como inserção em massa) em um único transação:

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

Por padrão, Sqlite envolve todas as inserções em uma transação, que diminui o processo:

Inserir é muito lento - só posso fazer poucas dezenas de inserções por segundo

Na verdade, o SQLite fará facilmente 50.000 declarações de inserção por segundo em um computador de mesa média. Mas fará apenas algumas dezenas de transações por segundo.

A velocidade da transação é limitada pela velocidade da unidade de disco porque (por padrão) o sqlite realmente aguarda até que os dados sejam realmente armazenados com segurança na superfície do disco antes da conclusão da transação. Dessa forma, se você perder de repente poder ou se seu sistema operacional travar, seus dados ainda estarão seguros. Para detalhes, leia sobre o comprometimento atômico em Sqlite ..

Por padrão, cada declaração de inserção é sua própria transação. Mas se você cercar várias declarações de inserção com BEGIN ... COMMIT, todas as inserções serão agrupadas em uma única transação. O tempo necessário para cometer a transação é amortizado sobre todas as declarações de inserção fechada e, portanto, o tempo por instrução de inserção é bastante reduzido.

Eu li em todos os lugares que a criação de transações é a solução para diminuir o sqlite lento, mas pode ser longo e doloroso reescrever seu código e envolver todas as suas gravações de sqlite em transações.

Encontrei um método muito mais simples, seguro e muito eficiente: habilite um (desativado por padrão) sqlite 3.7.0 otimização: o Write-Ahead-Log (Wal). A documentação diz que funciona em todos os sistemas UNIX (ou seja, Linux e OSX) e Windows.

Como ? Basta executar os seguintes comandos depois de inicializar sua conexão SQLite:

PRAGMA journal_mode = WAL
PRAGMA synchronous = NORMAL

Meu código agora é executado ~ 600% mais rápido: minha suíte de teste agora é executada em 38 segundos em vez de 4 minutos :)

Consulte "Otimizando as consultas SQL" no arquivo ADO.NET Ajuda SQLITE.NET.CHM. Código dessa página:

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();
}
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top