我正在尝试使用Python脚本来解析Wikipedia档案。 (是的,我知道。)当然:
这排除了将文件加载到内存中的情况,进入虚拟内存的情况不会好得多。因此,为了处理数据,我决定将必要的信息解析到SQLite数据库中。对于XML解析,我使用了ElementTree库,该库的性能很好。我确认只运行XML解析(只是注释掉数据库调用)它是线性运行的,并且遍历文件时不会降低速度。
问题在于试图将数百万行插入SQLite数据库(每篇Wikipedia文章)。我用于测试的表的简单版本如下:
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
和COMMIT TRANSACTION
调用自己(因此整个解析序列是一个事务),但这仍然无济于事。
某些other questions on this site表示索引是问题。我桌上没有任何索引。我确实尝试删除了UNIQUE
约束并将其限制为id INTEGER PRIMARY KEY
和title TEXT NOT NULL
,但这也没有效果。
在大型数据集中使用SQLite执行这些类型的插入的最佳方法是什么?当然,这个简单的查询只是众多查询中的第一个。还有其他查询会更复杂,涉及外键(此表中文章的ID)以及嵌入了select的insert语句(在插入过程中从articles表中选择一个ID)。这些注定会遇到相同的问题,但又大幅度加剧了该情况-article表的行数少于1500万,其他表的行数可能超过10亿。因此,这些性能问题更加令人担忧。
我正在尝试使用Python脚本来解析Wikipedia档案。 (是的,我知道。)当然:Wikipedia XML:45.95 GB可用内存:16 GB这排除了将文件加载到内存中,然后进行...
插入时发生的一件“不可见”事情是更新表的索引(并检查与索引相关的约束,例如UNIQUE)。由于无论如何您都忽略UNIQUE违规,您可能会发现在加载表时禁用表上的索引很有用,如果确实需要它们,则在加载完成后立即构建索引。