在没有详细介绍的情况下,我的iOS应用程序中有一个进程,它解析XML并将数千条记录(有时最多10或100)插入到Sqlite3表中。
为了速度,我在表上没有索引,我首先将记录插入内存临时表中,然后以400的批量将它们移动到最终表中。临时表或文件系统表都没有任何索引
我注意到的问题是,在流程开始时,将400条记录刷新到磁盘需要大约10秒钟。然后每次冲洗,需要更长时间,在一两分钟后,需要3秒钟来冲洗400条记录。它越长,所需的时间越长。每次冲洗比前一次冲洗需要大约1至2分之一秒。
由于我没有使用任何索引,有人可以解释为什么会这样,并推荐一个解决方案吗?
更新1:
我试着设置PRAGMA syncronous = OFF;
,虽然加速了一点,但是每隔INSERT SELECT
它仍然会慢一点点,在几千行之后每次冲洗都是多秒。我将继续尝试其他优化,看看我是否可以深入了解...
更新2: 澄清我正在做什么:我正在将记录插入到内存中的临时表中,直到计数达到400(由Objective-C代码中的int计算)。一旦记录计数为400,我正在执行单个INSERT SELECT将行移动到磁盘上的表中,然后我从内存表中执行DELETE *。我正在为每个部分计时。 Sqlite3在没有WHERE子句时优化DELETE *,这样就像删除并重新创建表一样,并且它非常快,不到100秒。它只是从内存表到磁盘表的INSERT SELECT,每次都在降低速度。该查询开始花费大约0.1秒,并且在插入的每批400条记录之后,查询比最后一条记录花费大约.1到.2秒,直到它最终花费多秒钟将400行从内存移动到每次都是磁盘。
更新3:这是我的表创建语句和我用来将记录从内存移动到磁盘的语句。根本没有钥匙。是的,我的sqlite已配置,以便临时表在内存而不是磁盘。
内存中的临时表:
CREATE TEMPORARY TABLE allSongsTemp (title TEXT, songId TEXT, artist TEXT, album TEXT, genre TEXT, coverArtId TEXT, path TEXT, suffix TEXT, transcodedSuffix TEXT, duration INTEGER, bitRate INTEGER, track INTEGER, year INTEGER, size INTEGER);
磁盘上的表:
CREATE TABLE allSongsUnsorted (title TEXT, songId TEXT, artist TEXT, album TEXT, genre TEXT, coverArtId TEXT, path TEXT, suffix TEXT, transcodedSuffix TEXT, duration INTEGER, bitRate INTEGER, track INTEGER, year INTEGER, size INTEGER);
将内存记录刷新到磁盘的查询:
INSERT INTO allSongsUnsorted SELECT * FROM allSongsTemp;
DELETE * FROM allSongsTemp;
每次越来越长的查询是#3,即INSERT SELECT
。 DELETE
每次大约需要1/100秒。
答案 0 :(得分:0)
了解交易,以及您应该使用它们的原因。如果进行单独插入,则每个插入必须经历开始/结束事务周期,并且开销很大。执行批量插入/更新操作时,请始终先执行启动事务。
答案 1 :(得分:0)
您的密钥是什么样的,并且您在此表上是否有任何唯一的列/约束?一个定义(如果实名太过暴露,改变了列名)将有助于诊断问题,但我的猜测将是你的表定义中某处的潜行唯一约束。
答案 2 :(得分:0)
Larry Lustig在对这个问题的评论中称之为,但似乎不再能够创造答案了。
删除并重新创建表而不是执行DELETE *
就可以了。虽然删除速度很快,但它在内存中造成了某种碎片,导致每次后续读取变慢。除非我误读了sqlite3文档,否则DELETE *
应该被优化为DROP; CREATE;
,但对于临时内存表(或者甚至可能是文件系统表)来说,似乎可能并非如此,但我需要测试验证,因为这个问题很可能只影响内存表。)