2010-12-04 2 views
12

В моей системе ~ 86000 вставок SQLite заняли до 20 минут, значит ~ 70 вставок в секунду. Я должен делать миллионы, как я могу ускорить его? Вызов Open() и Close() объекта SQLiteConnection для каждой строки может замедлить производительность? Могут ли транзакции помочь?Производительность SQLite .NET, как ускорить работу?

Типичный метод вставки для одной строки:

public int InsertResultItem(string runTag, int topicId, 
     string documentNumber, int rank, double score) 
    { 
     // Apre la connessione e imposta il comando 
     connection.Open(); 

     command.CommandText = "INSERT OR IGNORE INTO Result " 
      + "(RunTag, TopicId, DocumentNumber, Rank, Score) " + 
      "VALUES (@RunTag, @TopicId, @DocumentNumber, @Rank, @Score)"; 

     // Imposta i parametri 
     command.Parameters.AddWithValue("@RunTag", runTag); 
     command.Parameters.AddWithValue("@TopicId", topicId); 
     command.Parameters.AddWithValue("@DocumentNumber", documentNumber); 
     command.Parameters.AddWithValue("@Rank", rank); 
     command.Parameters.AddWithValue("@Score", score); 

     // Ottieni il risultato e chiudi la connessione 
     int retval = command.ExecuteNonQuery(); 
     connection.Close(); 

     return retval; 
    } 

Как вы можете видеть, Вставки очень простые.

ответ

23

Вам определенно необходима сделка. Если вы этого не сделаете, SQLite начнет свою собственную транзакцию для каждой команды вставки, чтобы эффективно выполнять 86000 транзакций.

Кажется, вы также открываете и закрываете соединение каждый раз, а также каждый раз сбрасываете CommandText. Это не является необходимым, и, несомненно, замедляет вас, он будет идти гораздо быстрее, если вы:

  • Открыть соединение сразу
  • Построить команду один раз, добавляя параметры к нему один раз.
  • Запустите транзакцию
  • Loop через, изменяя значения параметров только перед вызовом ExecuteNonQuery
  • Подтверждать транзакцию.
  • Закройте соединение.

Я думаю, что вы могли бы сократить свои 20 минут до нескольких секунд таким образом.

Edit: это то, что я имею в виду:

public void InsertItems() 
{ 
    SQLiteConnection connection = new SQLiteConnection(SomeConnectionString); 
    SQLiteCommand command = connection.CreateCommand(); 
    SQLiteTransaction transaction = connection.BeginTransaction(); 

    command.CommandText = "INSERT OR IGNORE INTO Result " 
+ "(RunTag, TopicId, DocumentNumber, Rank, Score) " + 
    "VALUES (@RunTag, @TopicId, @DocumentNumber, @Rank, @Score)"; 

    command.Parameters.AddWithValue("@RunTag", ""); 
    command.Parameters.AddWithValue("@TopicId", ""); 
    command.Parameters.AddWithValue("@DocumentNumber", ""); 
    command.Parameters.AddWithValue("@Rank", ""); 
    command.Parameters.AddWithValue("@Score", ""); 

    foreach (/* item to loop through and add to db */) 
    { 
     InsertResultItem(runTag, topicId, documentNumber, rank, score, command); 
    } 

    transaction.Commit(); 
    command.Dispose(); 
    connection.Dispose(); 
} 

public int InsertResultItem(string runTag, int topicId, string documentNumber, int rank, double score, SQLiteCommand command) 
{ 
    command.Parameters["@RunTag"].Value = runTag; 
    command.Parameters["@TopicId"].Value = topicId; 
    command.Parameters["@DocumentNumber"].Value = documentNumber; 
    command.Parameters["@Rank"].Value = rank; 
    command.Parameters["@Score"].Value = score; 
    return command.ExecuteNonQuery(); 
} 

Он использует только одно соединение, одну транзакцию и одну команду, так что все вы изменяете это значения параметров каждый раз.

3

Использование транзакций. Это должно ускорить работу. Также я порекомендую вам следующую схему:

public int InsertResultItem(string runTag, int topicId, 
    string documentNumber, int rank, double score) 
{ 
    // Apre la connessione e imposta il comando 
    using (var connection = new SQLiteConnection(SomeConnectionString)) 
    using (var command = new connection.CreateCommand()) 
    { 
     connection.Open(); 
     using (var tx = connection.BeginTransaction()) 
     { 
      command.CommandText = "INSERT OR IGNORE INTO Result " 
       + "(RunTag, TopicId, DocumentNumber, Rank, Score) " + 
       "VALUES (@RunTag, @TopicId, @DocumentNumber, @Rank, @Score)"; 

      // Imposta i parametri 
      command.Parameters.AddWithValue("@RunTag", runTag); 
      command.Parameters.AddWithValue("@TopicId", topicId); 
      command.Parameters.AddWithValue("@DocumentNumber", documentNumber); 
      command.Parameters.AddWithValue("@Rank", rank); 
      command.Parameters.AddWithValue("@Score", score); 

      // Ottieni il risultato e chiudi la connessione 
      var retval = command.ExecuteNonQuery(); 
      tx.Commit(); 
      return retval; 
     } 
    } 
} 
+0

Как в InsertResultItem кажется, что он будет вызываться в цикле, это все равно открывает новое соединение, начиная новую транзакцию и делая новую команду для каждой вставки. Скорость будет такой же, как и в коде OP. – mikel 2010-12-04 23:47:20

+0

@ miket2e, это не открывает новое соединение, ADO.NET использует пул соединений. Также начинается новая транзакция, что ускоряет работу. – 2010-12-04 23:48:35

Смежные вопросы