68

我最近阅读了有关 SQLite 的文章,并认为我会尝试一下。当我插入一条记录时,它执行得很好。但是当我插入一百个时,它需要五秒钟,并且随着记录数的增加,时间也会增加。有什么问题?我正在使用 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();
4

4 回答 4

88

围绕您的批量插入包装BEGIN\END语句。Sqlite 针对事务进行了优化。

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();
于 2010-10-04T00:07:17.360 回答
44

我到处都读到创建事务是减缓 SQLite 写入速度的解决方案,但是重写代码并将所有 SQLite 写入包装在事务中可能会很长而且很痛苦。

我找到了一个更简单、安全且非常有效的方法:我启用(默认禁用)SQLite 3.7.0 优化:Write-Ahead-Log (WAL)。文档说它适用于所有 unix(即 Linux 和 OSX)和 Windows 系统。

如何 ?初始化 SQLite 连接后,只需运行以下命令:

PRAGMA journal_mode = WAL
PRAGMA synchronous = NORMAL

我的代码现在运行速度快了约 600%:我的测试套件现在可以在 38 秒内运行,而不是 4 分钟 :)

于 2014-12-04T09:16:58.480 回答
33

尝试将所有插入(又名批量插入)包装到单个事务中:

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

默认情况下,SQLite 将每个插入包装在一个事务中,这会减慢进程:

INSERT 真的很慢 - 我每秒只能做几十个 INSERT

实际上,SQLite 在普通台式计算机上每秒可以轻松执行 50,000 或更多的 INSERT 语句。但它每秒只会进行几十次交易。

事务速度受到磁盘驱动器速度的限制,因为(默认情况下)SQLite 实际上会等到数据真正安全地存储在磁盘表面上之后才会完成事务。这样,如果您突然断电或操作系统崩溃,您的数据仍然是安全的。有关详细信息,请阅读 SQLite 中的原子提交。

默认情况下,每个 INSERT 语句都是它自己的事务。但是,如果您使用 BEGIN...COMMIT 包围多个 INSERT 语句,则所有插入都将分组到一个事务中。提交事务所需的时间在所有封闭的插入语句中分摊,因此每个插入语句的时间大大减少。

于 2010-10-04T00:09:11.423 回答
8

请参阅 ADO.NET 帮助文件 SQLite.NET.chm 中的“优化 SQL 查询”。该页面的代码:

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();
}
于 2011-01-21T05:53:25.690 回答