Подтвердить что ты не робот

Производительность SQLite.NET, как ускорить работу?

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

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

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

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

4b9b3361

Ответ 1

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

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

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

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

Изменить: вот что я имею в виду:

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

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

Ответ 2

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

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