加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 百科 > 正文

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

发布时间:2020-12-12 18:54:25 所属栏目:百科 来源:网络整理
导读:SOLVED: CL.’s comment solved it – increasing the cache size works. Apparently primary keys are very memory heavy during inserts on large tables. 我正在尝试使用Python脚本来解析Wikipedia档案. (是的,我知道.)当然: 维基百科XML:45.95 GB 可用

SOLVED: CL.’s comment solved it – increasing the cache size works. Apparently primary keys are very memory heavy during inserts on large tables.

我正在尝试使用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().根据我读过的内容,只要只有INSERT语句,executemany()就不应该在db.commit()之前提交事务.

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

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

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

解决方法

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

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

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读