我正在尝试使用 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 TRANSACTION
andCOMMIT TRANSACTION
调用自己(因此整个解析序列是一个事务),但它仍然没有帮助。
该站点上的其他一些问题表明索引是问题所在。我的桌子上没有任何索引。我确实尝试删除UNIQUE
约束并将其限制为id INTEGER PRIMARY KEY
andtitle TEXT NOT NULL
但这也没有效果。
在 SQLite 中为大型数据集执行这些类型的插入的最佳方法是什么?当然,这个简单的查询只是众多查询中的第一个;还有其他查询会更复杂,涉及外键(此表中文章的 ID)以及嵌入了选择的插入语句(在插入期间从文章表中选择一个 ID)。这些必然会有同样的问题,但会大大加剧 - 文章表的行数少于 1500 万行,而其他表的行数可能会超过 10 亿行。因此,这些性能问题更加令人担忧。