在 SQLite + BEGIN TRANSACTION 中更新更快

Posted

技术标签:

【中文标题】在 SQLite + BEGIN TRANSACTION 中更新更快【英文标题】:UPDATE faster in SQLite + BEGIN TRANSACTION 【发布时间】:2014-08-18 03:38:02 【问题描述】:

这个也与 spatilite 相关(不仅是 SQLite)

我有一个 文件数据库 (xyz.db),SQLiteconnection 正在使用它(SQLiteconnection 扩展到了 spatialite)。

我有很多记录需要更新到数据库中。

                for (int y = 0; y < castarraylist.Count; y++)
                
                    string s = Convert.ToString(castarraylist[y]);

                    string[] h = s.Split(':');

                    SQLiteCommand sqlqctSQL4 = new SQLiteCommand("UPDATE temp2 SET GEOM = " + h[0] + "WHERE " + dtsqlquery2.Columns[0] + "=" + h[1] + "", con);
                    sqlqctSQL4.ExecuteNonQuery();

                    x = x + 1;
                

在上面的逻辑castarraylistArraylist,其中包含需要处理到数据库中的值。

当我检查上面的代码时,1 分钟内更新了大约 400 条记录。

有什么方法可以提高性能吗?

注意 ::(文件数据库不是线程安全的)

2。开始交易

假设我喜欢在 Spatialite 中使用单个事务运行两个(或数百万个)更新语句。这可能吗?

我在线阅读并为我准备了以下声明(但没有成功)

BEGIN TRANSACTION;
UPDATE builtuparea_luxbel SET ADMIN_LEVEL = 6 where PK_UID = 2;
UPDATE builtuparea_luxbel SET ADMIN_LEVEL = 6 where PK_UID = 3;
COMMIT TRANSACTION; 

以上语句未更新我的数据库中的记录。 SQLite 不支持 BEGIN TRANSACTION 吗? 有什么我想念的吗?

如果我需要运行单个语句,那么如上所述更新需要花费太多时间......

【问题讨论】:

【参考方案1】:

SQLite 支持事务,你可以试试下面的代码。

using (var cmd = new SQLiteCommand(conn))
using (var transaction = conn.BeginTransaction())

    for (int y = 0; y < castarraylist.Count; y++)
    
        //Add your query here.
        cmd.CommandText = "INSERT INTO TABLE (Field1,Field2) VALUES ('A', 'B');";
        cmd.ExecuteNonQuery();
    
    transaction.Commit();

【讨论】:

这个逻辑和上面的有什么不同?因为这里我们也运行 for 循环,它循环了 1000 次 你可以看到上面的查询将对castarraylist中的所有记录执行,完成后事务将提交,你可以试试上面的代码看看结果。 是的,它有所改进,但仍然无效。对于 100000 条记录,它需要 > 50 分钟。所以我手动收集了执行每组 5000 条记录的时间。我注意到它在增加每一束的时间。 5000 条记录处理时间 1st > 1:11 分钟 2nd > 1:25 分钟 3rd > 1:32 分钟 4th > 1:40 分钟 5th > 1:47 分钟 6th > 1:52 分钟 ... ... 17th > 18 日 3:32 分钟 > 19 日 3:44 分钟 > 20 日 4:02 分钟 > 4:56 分钟 为什么会这样?需要运行其他一些内存增量命令吗? 你不应该重复使用 SQLiteCommand 对象来执行如此重要的查询:它会导致内存开销。【参考方案2】:

数据库事务的主要目标完成所有事情,如果内部出现故障,则什么都不做

重复使用相同的 SQLiteCommand 对象,通过更改其 CommandText 属性并一次又一次地执行它可能会更快,但 会导致内存开销:如果您有要执行的查询量很大,最好是在使用后处理对象并创建一个新对象;

ADO.NET 事务的常见模式是:

using (var tra = cn.BeginTransaction())

    try
     
        foreach(var myQuery in myQueries)
         
            using (var cd = new SQLiteCommand(myQuery, cn, tra))
            
                cd.ExecuteNonQuery();
            
        

        tra.Commit();
    
    catch(Exception ex)
    
        tra.Rollback();
        Console.Error.Writeline("I did nothing, because something wrong happened: 0", ex);
        throw;
    

【讨论】:

你怎么知道它会导致内存开销? 任务管理器中的私有内存使用情况。当我正确处理 SQLiteCommand 时,它不会发生。 This behavior has been also seen here。还有here。顺便说一句,如果有解决方案,我很感兴趣:)

以上是关于在 SQLite + BEGIN TRANSACTION 中更新更快的主要内容,如果未能解决你的问题,请参考以下文章

在 SQLite + BEGIN TRANSACTION 中更新更快

用transact-sql 2000程序设计求1-100之间偶数的和,并输出结果

system.reflection.targetinvocationexception SQLite

SQLite也可能出现死锁

sqlit3事务

Sqlite3插入大量数据性能优化