合并SQLite数据库让我崩溃,求助?
我有32个SQLite(3.7.9)数据库,每个数据库里有3个表,我想把它们合并在一起。每个数据库的结构都是一样的:
attach db1.sqlite3 as toMerge;
insert into tbl1 select * from toMerge.tbl1;
insert into tbl2 select * from toMerge.tbl2;
insert into tbl3 select * from toMerge.tbl3;
detach toMerge;
然后对所有的数据库重复这个过程。我是用Python和sqlite3模块来做这个的:
for fn in filelist:
completedb = sqlite3.connect("complete.sqlite3")
c = completedb.cursor()
c.execute("pragma synchronous = off;")
c.execute("pragma journal_mode=off;")
print("Attempting to merge " + fn + ".")
query = "attach '" + fn + "' as toMerge;"
c.execute(query)
try:
c.execute("insert into tbl1 select * from toMerge.tbl1;")
c.execute("insert into tbl2 select * from toMerge.tbl2;")
c.execute("insert into tbl3 select * from toMerge.tbl3;")
c.execute("detach toMerge;")
completedb.commit()
except sqlite3.Error as err:
print "Error! ", type(err), " Error msg: ", err
raise
其中有两个表比较小,每个数据库大约有5万行数据,而第三个表(tbl3)就大得多,大约有85万到90万行数据。现在的问题是,插入数据的速度逐渐变慢,到了第四个数据库的时候几乎停滞不前(合并后的数据库每1到3分钟才增加一两兆的文件大小)。为了排除是Python的问题,我甚至尝试把表的数据导出为INSERT语句(.insert; .out foo; sqlite3 complete.db < foo是基本的做法,具体可以在这里找到),然后用bash脚本直接用sqlite3命令行工具来合并,但问题依旧。
tbl3的表结构并不复杂,包含一个UUID的文本字段、两个整数和四个实数。我担心的是行数太多,因为我在合并的时候也遇到了同样的问题,正好是在第四个数据库的时候,那时每个数据库的文件大小大得多,但行数是一样的(我把tbl3的内容大幅精简,只存储了汇总统计而不是原始数据)。或者说,是我执行操作的方式有问题?在我快要崩溃之前,有谁能帮我分析一下我遇到的问题吗?
2 个回答
你没有提到你使用的操作系统和数据库文件的大小。根据不同的版本,Windows在处理超过2GB的文件时可能会遇到问题。
无论如何,既然这个东西其实就是个升级版的批处理脚本,为什么不去掉for
循环呢?可以直接从sys.argv
获取文件名,然后对每个合并的数据库运行一次。这样你就不需要担心在一个进程中处理太多数据导致的内存问题。
另外,如果你在循环结束时加上以下代码,可能也能解决问题。
c.close()
completedb.close()
你说在使用命令行界面(CLI)时,按照这个流程操作,每处理完一个数据库就退出,结果也会出现同样的问题。我猜你指的是Python的命令行界面,退出就是指你关闭然后重新启动Python。如果是这样的话,每处理第四个数据库就出现问题,那可能是你的SQLITE共享库有问题。它不应该保持这样的状态。
如果我是你,我会停止使用attach
,而是在Python中打开多个连接,然后每次处理大约1000条记录的数据。虽然这样会比你的方法慢,因为所有数据都要在Python对象之间移动,但我觉得这样会更可靠。先打开完整的数据库,然后循环打开第二个数据库,复制数据后再关闭第二个数据库。在复制数据时,我会在SELECT语句中使用OFFSET和LIMIT来处理每100条记录,然后提交,再重复这个过程。实际上,我还会在复制之前统计完整数据库和第二个数据库的记录数,然后在复制后再统计一次完整数据库的记录数,以确保我复制了预期的数量。此外,我会跟踪下一个OFFSET的值,并在每次提交后将其写入一个文本文件,这样我可以随时中断并重新启动这个过程,并且可以从上次中断的地方继续。
试着为更大的表添加或删除索引/主键。