2014-07-04 18 views
2

我有SQLite database (.db)性能问题与SQLite数据库(.db的)

我试图更新1,00,000记录数据库(.db的),它以大约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 GHz4 GB RAM500 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获取的记录。

以下语句扩展Spatialite上的SQLite

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语句(现在用拉里的代码提示)

+2

什么实际执行的SQL命令? –

+2

为什么GC.Collect()? – Larry

+0

@CL。实际的命令是在** castarraylist ** – Hardik

回答

3

Currencly,交易每次查询,这是没有意义的运行。

将事务中的主循环代码括起来,并删除此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(); 
} 
+0

@Larry ...我用你的代码,我也把所有的价值在一个列表中。所以我的代码现在...'使用(var transaction = con.BeginTransaction()){尝试{使用(var cmd = new SQLiteCommand(con)){cmd.Transaction = transaction; for(int q = 0; q Hardik

+0

@Larry ...目前此列表包含100万条记录...并且使用此代码单记录是失败总交易失败,所以有没有更简单的方法? – Hardik

+0

@Hardik哦,我明白了。我相应地调整了代码,所以如果记录因任何原因拒绝更新,它将不会回滚整个更改。我还改变了SQLLiteCommand对象的使用方式,因此不再使用。让我知道如果它是更好或不。 – Larry

3

首先,你应该尝试使用准备好的声明中有更好的表现。查看System.Data.SQLite文档,以便您可以使用SQLiteParameter并在循环中设置参数值。

其次,ArrayList应该比List或阵列慢。也许改变这可以帮助。

第三,可能会有一些Pragma commands就可以使用。

编辑:我看你已经关闭同步和journal_mode,我不知道有你应该使用任何其他编译。在某些情况下,locking_mode = EXCLUSIVE和temp_store = MEMORY会很有帮助。

+0

@Griddor ...我没有传递任何参数值。我在另一个线程中直接声明语句...我尝试使用'LIST',但它的性能没有得到提高..是的,大多数人都知道我在连接数据库时使用的所有Pragma命令 – Hardik

+1

@Hardik实际上准备好的语句是使用SQLite,只能改变循环中的参数值。直接执行查询意味着为每个单独的查询准备语句。此外,就像拉里的回答一样,在所有循环都应该比多次提交更快之后,只提交一次事务。 – cshu

2

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

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

  • 是否真的有必要在每次更新中进行自己的交易?你知道,如果你的代码失败并在这个循环的中途抛出一个异常,那么前半部分的更新将会被提交,但是你将不会有任何方法来回收你离开的地方?你甚至不会有一个简单的方法知道你离开的地方。

  • 是否有任何特定原因使用ArrayList而不是列表<T>?这会导致你需要在内部循环中执行一次强制转换并调用Convert.ToString,这不应该是必须的(除非你有使用ArrayList的非常好的理由)。

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; 
+0

@CL ...是的,我创建了INDEX,它确实很 – Hardik

+0

但我认为我无法创建主键,因为我有时会插入多于1列,并且它们不是预定义的。 – Hardik

+0

当前正面临着问题... UPDATE语句我在不同的线程中创建它,它在哪里内存异常在字符串和数组上。 – Hardik