SQLite在Python上插入数百万行的性能

时间:2013-11-14 09:28:07

标签: python sql database sqlite large-data

  

解决:CL。的评论解决了它 - 增加缓存大小的工作原理。显然,在大型表格上插入主键时内存很重。

我正在尝试使用Python脚本来解析Wikipedia档案。 (是的,我知道。)当然:

  • 维基百科XML:45.95 GB
  • 可用内存:16 GB

这样就无法将文件加载到内存中,进入虚拟内存的情况也不会好得多。因此,为了处理数据,我决定将必要的信息解析为SQLite数据库。对于XML解析,我使用了ElementTree库,它执行得非常好。我确认只运行XML解析(只是注释掉数据库调用),它以线性方式运行,并且在遍历文件时没有减速。

问题在于尝试将数百万行插入SQLite数据库(每个维基百科文章一个)。我用于测试的表的简单版本如下:

CREATE TABLE articles(
    id INTEGER NOT NULL PRIMARY KEY,
    title TEXT NOT NULL UNIQUE ON CONFLICT IGNORE);

所以我在这个初始阶段只有id和一个文本字段。当我开始通过以下方式添加行时

INSERT OR IGNORE INTO articles(title) VALUES(?1);

起初表现良好。但是在大约800万行中,它开始急剧减速,达到一个数量级或更多。

当然需要一些细节。我使用cur.executemany()在insert语句之前创建了一个游标。每次调用此函数都有一批约100,000行。在插入所有百万行之前,我不会调用db.commit()。根据我所读到的,executemany()只要只有INSERT语句,就不应该在db.commit()之前提交事务。

正在读取的源XML和正在编写的数据库位于两个独立的磁盘上,我也尝试在内存中创建数据库,但无论如何我都看到了减速。我还尝试了isolation_level=None选项,在开头和结尾自己添加BEGIN TRANSACTIONCOMMIT TRANSACTION调用(因此整个解析序列是一个事务),但它仍然没有帮助。

有些other questions on this site表示索引是问题所在。我桌子上没有任何索引。我确实尝试删除了UNIQUE约束,只是将其限制为id INTEGER PRIMARY KEYtitle TEXT NOT NULL,但这也没有效果。

在SQLite中为大型数据集执行这些类型的插入的最佳方法是什么?当然,这个简单的查询只是众多中的第一个;还有其他查询将更复杂,涉及外键(此表中的文章的ID)以及嵌入了选择的insert语句(在插入期间从articles表中选择id)。这些问题肯定会出现同样的问题,但会大幅加剧 - 文章表的行数少于1500万行,其他表可能会有超过10亿行。所以这些性能问题更令人担忧。

1 个答案:

答案 0 :(得分:3)

插入时发生的一个“不可见”事情是更新表的索引(并检查索引相关的约束,如UNIQUE)。由于你无论如何都忽略了UNIQUE违规,你可能会发现在加载表时禁用表上的索引很有用,如果你真的需要它们,请在加载完成后构建索引一次。

但请注意,SQLite对小数据的闪电速度来自某些隐含的假设,这些假设在处理大数据时会越来越严重。它可能不适合您当前硬件上的当前问题。