合并 SQLite 数据库让我发疯。帮助?

Posted

技术标签:

【中文标题】合并 SQLite 数据库让我发疯。帮助?【英文标题】:Merging SQLite databases is driving me mad. Help? 【发布时间】:2011-11-25 03:27:42 【问题描述】:

我有 32 个 SQLite (3.7.9) 数据库,每个数据库有 3 个表,我尝试使用我在其他地方找到的习语将它们合并在一起(每个 db 具有相同的架构):

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

其中 2 个表相当小,每个 db 只有 50K 行,而第三个 (tbl3) 较大,大约 850 - 900K 行。现在,发生的情况是插入逐渐变慢,直到我到达大约第四个数据库,当它们几乎停止时(大约每 1-3 分钟向组合数据库添加一兆字节或两兆字节的文件大小)。如果是 python,我什至尝试将表作为 INSERT (.insert; .out foo; sqlite3 complete.db here) 并使用 sqlite3 将它们组合在 bash 脚本中CLI 直接完成这项工作,但我遇到了完全相同的问题。

tbl3 的表格设置要求并不高——一个包含 UUID、两个整数和四个实数值的文本字段。我担心的是行数,因为当单个数据库在具有相同行数的文件大小方面大一个数量级时,我在完全相同的位置(大约四个数据库)遇到了完全相同的问题(我通过存储摘要统计而不是原始数据来显着修剪 tbl3 的内容)。或者也许这是我执行操作的方式?在我把东西扔出窗外之前,谁能解释一下我遇到的这个问题?

【问题讨论】:

【参考方案1】:

尝试为更大的表添加或删除索引/主键。

【讨论】:

【参考方案2】:

您没有提及您使用的操作系统或数据库文件大小。 Windows 可能会遇到大于 2Gb 的文件的问题,具体取决于版本。

无论如何,既然这是一个美化的批处理脚本,为什么不摆脱for 循环,从sys.argv 获取文件名,然后为每个合并数据库运行一次。这样一来,您将永远不必处理因在一个进程中执行过多操作而导致的内存问题。

请注意,如果您使用以下内容结束循环,也可能会解决问题。

c.close()
completedb.close()

您说当您使用 CLI 执行此过程并在每个 db 之后退出时会发生同样的事情。我假设您指的是 Python CLI,而退出意味着您退出并重新启动 Python。如果这是真的,并且每隔 4 个数据库就会出现问题,那么您的 SQLITE 共享库有问题。它不应该保持这样的状态。

如果我站在你的立场上,我会停止使用attach,而只是在 Python 中打开多个连接,然后以每次提交约 1000 条记录的批量移动数据。它会比您的技术慢,因为所有数据都会进出 Python 对象,但我认为它也会更可靠。打开完整的数据库,然后循环打开第二个数据库,复制,然后关闭第二个数据库。对于复制,我会在 SELECT 语句上使用 OFFSET 和 LIMIT 来处理 100 条记录的批次,然后提交,然后重复。 其实我也会统计completedb的记录,复制前第二个db的记录,复制之后再统计completedb的记录,确保我已经复制了预期的数量。此外,您将跟踪下一个 OFFSET 的值,我会在提交后立即将其写入文本文件,以便我可以随时中断并重新启动该过程,它会从中断处继续。

【讨论】:

迈克尔,感谢您的回答。回复:您的问题,我已经在 OS X Lion 和 Rocks 集群(5.3)的头节点上进行了尝试。正如我所提到的,问题与数据库文件大小无关。在当前的版本中,它们每个都是 160 Mb,但是当它们是 1.6 Gb 时,问题的出现方式完全相同。重新提出您的建议:我之前尝试使用 c.close() 和 completedb.close() 但将其排除在此代码之外 - 它没有解决问题。我什至尝试使用 CLI 手动执行此操作 - 启动它、附加、合并、退出,然后对每个文件重复。没有运气。

以上是关于合并 SQLite 数据库让我发疯。帮助?的主要内容,如果未能解决你的问题,请参考以下文章

UIScrollView 并不总是滚动让我发疯

基本的 jQuery slideUp 和 slideDown 让我发疯!

Influx CLI 让我发疯,无法打开 CLI

自定义 UITableViewCell 创建了两次......让我发疯

React 将受控错误变为不受控制的错误让我发疯,我做错了啥?

曼哈顿距离过高估计让我发疯