4

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

  • 维基百科 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()在插入语句之前创建的单个游标。对该函数的每次调用都有一批大约 100,000 行。在插入所有百万+行之前,我不会调用 db.commit() 。根据我所阅读的内容,executemany()只要只有INSERT语句,就不应该在 db.commit() 之前提交事务。

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

该站点上的其他一些问题表明索引是问题所在。我的桌子上没有任何索引。我确实尝试删除UNIQUE约束并将其限制为id INTEGER PRIMARY KEYandtitle TEXT NOT NULL但这也没有效果。

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

4

1 回答 1

3

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

但也要注意,SQLite 对小数据的闪电般的速度来自某些隐含的假设,当您处理大数据时,这些假设会越来越多地被违反。它可能不是解决当前硬件上当前问题的合适工具。

于 2013-11-14T12:26:01.793 回答