C# SQLite.NET性能如何提高?

C# SQLite.NET性能如何提高?,c#,.net,performance,sqlite,insert,C#,.net,Performance,Sqlite,Insert,在我的系统上,大约86000次SQLite插入耗时20分钟,即每秒约70次插入。我要做几百万,我怎样才能加快速度?对每行SQLiteConnection对象调用Open()和Close()会降低性能吗?交易有帮助吗 单线的典型插入方法: public int InsertResultItem(string runTag, int topicId, string documentNumber, int rank, double score) { //

在我的系统上,大约86000次SQLite插入耗时20分钟,即每秒约70次插入。我要做几百万,我怎样才能加快速度?对每行SQLiteConnection对象调用Open()和Close()会降低性能吗?交易有帮助吗

单线的典型插入方法:

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

如您所见,插入非常简单。

使用事务。这会让事情变得更快。此外,我还向您推荐以下模式:

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

你肯定需要一笔交易。如果您不这样做,SQLite会为每个insert命令启动自己的事务,这样您就可以按原样有效地执行86000个事务

看起来您每次都在打开和关闭连接,同时每次都重置CommandText。这是不必要的,毫无疑问会让你慢下来,如果你:

  • 打开连接一次
  • 生成一次命令,向其中添加一次参数
  • 启动事务
  • 循环,仅在调用ExecuteOnQuery之前更改参数值
  • 提交事务
  • 关闭连接
我想这样你可以把你的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();
}

它只使用一个连接、一个事务和一个命令,所以每次更改的只是参数值

由于InsertResultItem看起来像是在循环中调用的,这仍然是打开一个新连接,启动一个新事务,并为每个插入生成一个新命令。速度与OP代码中的速度相同。@miket2e,这不是打开新连接,ADO.NET使用连接池。另外,启动一个新事务正是加快速度的原因。不过,它为每个插入创建一个事务。SQLite是隐式的()如果您没有显式地声明它,这就是我所说的相同的意思。它需要是一个围绕所有插入的事务,才能发挥作用。我不确定他是否在使用ADO.NET,如果他在应用程序中使用嵌入的SQLite(没有ADO.NET),那么只连接一次也会更快。是的,每次提取新行时,循环都会调用InsertResultItem。所以使用事务是没有用的?不,它不是没有用的,事务会使它更快。您只需要对代码进行一点重构,以便只使用一个事务,而不是数千个事务。比方说,首先创建命令,然后将其作为参数传递给InsertResultItem-不要每次都重新创建它。我不能,因为循环在另一个类中。。。如何实现IDisposable并在Dispose()上提交事务?我认为如何实现它的细节实际上取决于您,只要您只使用一个连接/事务/命令,它将比您目前的速度快得多。从20分钟减少到1分钟。太棒了,感谢所有人!通过使用这个方法,我可以在时间上进一步减少1/4,使用更大的准备好的INSERT语句,一次插入10行,参数是原来的10倍。我认为它更快,因为它进行的本机互操作调用更少。我的性能指标:在不使用事务的情况下插入100行需要19832.0毫秒。使用事务插入10000行需要797.0毫秒。看起来交易是唯一的主导因素。