2

我遇到了性能问题SQLite database (.db)

我正在尝试更新数据库 (.db) 中的 1,00,000 条记录,这大约需要 50 分钟。太慢了。

我的代码如下::

        for (int q = 0; q < list.Count; q++) 
            { 
        ArrayList castarraylist = new ArrayList(); 
        castarraylist = (ArrayList)(list[q]); 

        using (var cmd = new SQLiteCommand(con)) 

            using (var transaction = con.BeginTransaction()) 
            { 
                cmd.Transaction = transaction; 

                for (int y = 0; y < castarraylist.Count; y++) 
                { 
                        cmd.CommandText = Convert.ToString(castarraylist[y]); 
                           cmd.ExecuteNonQuery(); 
                } 
                transaction.Commit(); 
                GC.Collect(); 
            } 
        } 

这里每个 castarraylist 包含 5000 条记录。使用事务更新到数据库中。所以循环遍历20次并完成全部更新。虽然我手动检查时间,但它会在每次迭代中增加 5000 条记录的时间。喜欢

1st 5000 records processing time > 1:11 minute

2nd 5000 records processing time > 1:25 minute

3rd  5000 records processing time > 1:32 minute 

4th 5000 records processing time > 1:40 minute 

5th 5000 records processing time > 1:47 minute 

6th 5000 records processing time > 1:52 minute 

...

... 

... 

17th 5000 records processing time > 3:32 minute 

18th 5000 records processing time > 3:44 minute

19th 5000 records processing time > 4:02 minute 

20th 5000 records processing time> 4:56 minute 

为什么会发生这种情况我无法理解。我用 C# 编写的源代码和我的笔记本电脑配置是i5 2.6 GHz, 4 GB RAM, 500 GB HD.

我建立了如下连接::

SQLiteConnection con = new SQLiteConnection("Data Source=" + fullPath + ";Version=3;Count Changes=off;Journal Mode=off;Pooling=true;Cache Size=10000;Page Size=4096;Synchronous=off"); 

(*fullpath - 是我的数据库路径)

我正在创建如下表...

sqlquery2="Select LINK_ID from RDF_LINK string createLinkToPoly = "create table temp2 AS " + sqlquery2;

这将创建一个表并插入由 sqlquery2 通过的记录。

下面的语句扩展了 SQLite 上的 Spatialite

ExecuteStatement("select load_extension('spatialite.dll')", con);

我的Update陈述如下::

UPDATE temp2 SET GEOM = Transform(LineStringFromText('LINESTRING(4.38368 51.18109,4.38427 51.18165)',4326),32632)WHERE LINK_ID= 53841546

所以这种100000条语句在不同的线程中构建并插入LIST

最后执行UPDATE上述代码中的语句(现在使用 Larry 建议的代码)

4

4 回答 4

3

首先,您应该尝试使用准备好的语句以获得更好的性能。查看 System.Data.SQLite 文档,以便您可以SQLiteParameter在循环中使用和设置参数值。

其次,ArrayList应该比List或Array慢。也许改变它会有所帮助。

第三,您可能会使用一些Pragma 命令

编辑:我看到你已经关闭了同步和日志模式,我不确定你应该使用任何其他编译指示。在某些情况下,locking_mode = EXCLUSIVE 和 temp_store = MEMORY 可能会有所帮助。

于 2014-07-04T07:38:24.207 回答
3

目前,事务是按查询运行的,这是没有意义的。

将您的主循环代码包含在事务中,并删除此 GC.Collect()。

编辑:

据我了解,您不希望在出现错误时回滚全局更新。所以我稍微改变了代码。

此外,我不确定是否可以通过更改 CommandText 并再次运行查询来重用命令对象。这就是为什么我建议每次都创建它。

using (var transaction = con.BeginTransaction()) 
{ 
    for (int q = 0; q < list.Count; q++) 
    { 
        var castarraylist = (ArrayList)(list[q]); 

        for (int y = 0; y < castarraylist.Count; y++) 
        { 
            using (var cmd = new SQLiteCommand(con)) 
            {
                cmd.Transaction = transaction; 
                cmd.CommandText = Convert.ToString(castarraylist[y]);
                try
                {
                    cmd.ExecuteNonQuery();
                }
                catch(Exception ex)
                {
                    // Log the update problem
                    Console.WriteLine("Update problem " + cmd.CommandText + " - Reason: " + ex.Message);
                }
            }
        }
    }

    transaction.Commit();
}
于 2014-07-04T07:45:05.853 回答
2

SQLite 可能没有性能问题;您几乎可以肯定自己的代码存在性能问题:

  • 几乎可以肯定根本不需要调用 GC.Collect()。你在这里所做的不应该造成任何显着的内存压力,如果是这样,我强烈建议让垃圾收集器自己做它自己的事情,而不是强迫这个问题。更糟糕的是,您在循环的每次迭代中都调用 GC.Collect() 。不要这样做!

  • 真的有必要在自己的事务中进行每个单独的更新吗?您确实意识到,如果您的代码在此循环中途失败并引发异常,则前半部分更新将已提交,但您将无法从中断的地方继续?你甚至不会有一个简单的方法知道你从哪里停下来。

  • 您使用 ArrayList 而不是 List<T> 有什么特别的原因吗?这导致您需要在内部循环中执行强制转换并调用 Convert.ToString,这不是必需的(除非您有非常非常好的理由使用 ArrayList)。

于 2014-07-04T10:11:27.870 回答
2

UPDATE 语句很慢,因为数据库必须扫描表中的所有记录才能找到任何匹配的 LINK_ID 值。您需要 LINK_ID 列上的索引。

在进行更新之前手动创建它:

CREATE INDEX temp2_linkid ON temp2(LINK_ID);

或者在创建表时创建索引(这需要显式创建表):

CREATE TABLE temp2 ( LINK_ID INTEGER PRIMARY KEY );
INSERT INTO temp2(LINK_ID) SELECT LINK_ID FROM RDF_LINK;
于 2014-07-04T16:29:33.347 回答