插入具有数百万行的性能

问题描述 投票:4回答:1

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

  • Wikipedia XML:45.95 GB
  • 可用内存:16 GB

这排除了将文件加载到内存中的情况,进入虚拟内存的情况不会好得多。因此,为了处理数据,我决定将必要的信息解析到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 TRANSACTIONCOMMIT TRANSACTION调用自己(因此整个解析序列是一个事务),但这仍然无济于事。

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

在大型数据集中使用SQLite执行这些类型的插入的最佳方法是什么?当然,这个简单的查询只是众多查询中的第一个。还有其他查询会更复杂,涉及外键(此表中文章的ID)以及嵌入了select的insert语句(在插入过程中从articles表中选择一个ID)。这些注定会遇到相同的问题,但又大幅度加剧了该情况-article表的行数少于1500万,其他表的行数可能超过10亿。因此,这些性能问题更加令人担忧。

我正在尝试使用Python脚本来解析Wikipedia档案。 (是的,我知道。)当然:Wikipedia XML:45.95 GB可用内存:16 GB这排除了将文件加载到内存中,然后进行...

python sql database sqlite large-data
1个回答
3
投票

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

© www.soinside.com 2019 - 2024. All rights reserved.