【问题标题】:JOIN of two large tables in two separate SQLite databases seems stuckJOIN 在两个单独的 SQLite 数据库中的两个大表似乎卡住了
【发布时间】:2019-08-01 21:37:24
【问题描述】:

上下文

我在两个单独的 SQlite 数据库 (db1,db2) 中有两个表 (A, B),我想合并(或加入,无论数据库中的正确术语是什么) . TABLE A 在 161GB 数据库 db1 中存储了大约 1.5 亿条记录,而 TABLE B 在 173GB 数据库db2 中存储了大约 2.92 亿条记录。我正在尝试通过 ATTACH-ing db2db1 并运行规范的 JOIN 查询来合并这两个表。

问题

下面的代码已经连续运行了 4 天以上,db1 数据库文件或其日志文件没有任何明显的变化。如果我使用 LIMIT 1000 子句运行测试查询,则 JOIN 将在不到一秒的时间内运行。对于全尺寸表,该操作似乎永远运行。我可以看到,正在从中读取数据的硬盘一直在 100% 使用,但它永远不会超出此范围(因此显然也没有输出显示)。

conn =  sqlite3.connect("/".join([data_path, 'db1.db']))
c = conn.cursor()

## attach 2nd db
query = """
ATTACH ".../db2.db" as db2;
"""
c.execute(query)
conn.commit()

## merge query
query = """
CREATE TABLE ABjoined AS
    SELECT  id,col2 FROM A INNER JOIN db2.B
    ON A.id = db2.B.id;
"""

c.execute(query)
c.commit()

更新

我很想创建一个最小的可重现示例,但似乎唯一的触发器是表大小。我只能考虑生成两个 150GB 的数据库进行合并,但这似乎不是最优的。我愿意接受建议

【问题讨论】:

  • 您是否考虑过 SQLite 可能不适合这项工作? (Lite 的存在是有原因的。)
  • @tonypdmtr 它开始引起人们的注意
  • @tonypdmtr 另一方面,SQlite 能够执行类似大小的 JOIN 操作,但它都在一个数据库中 - 而这里有两个数据库。也许这就是魔鬼藏身的地方
  • 根据sqlite.org/whentouse.html,数据库最高可达140TB。在实践中,它可能会起作用,但响应时间可能是“不可接受的”。我并不是说 SQLite3 不能处理这么多数据,但可能一个不同的引擎会做得更快。 SQLite3 的一大优点是使用单个文件来保存完整的数据库。然而,同样的事情可能会成为它最大的敌人,因为文件大小增长得太多,因为 FS/OS 引入的开销可能会大大减慢速度。只是在你的具体情况下猜测这是否是一个真正的问题。交易中的INSERT 有帮助。
  • @tonypdmtr 感谢您的建议!将表B 移动到db1,然后在db1 中执行合并。

标签: python sqlite join chunks


【解决方案1】:

似乎通过 ATTACH 合并表并不能很好地扩展 - 至少对于我的两个大表(即每个表至少 150,000,000 到 200)来说,通过 SQLite 中的附加数据库不能 很有效。如果遇到类似JOIN操作卡住的问题,建议将db2中的TABLE B移到db1中,然后像往常一样执行JOIN。即……

conn =  sqlite3.connect("/".join([data_path, 'db1.db']))
c = conn.cursor()

## attach 2nd db
query = """
ATTACH ".../db2.db" as db2;
"""
c.execute(query)

## create an empty table B in db1 and insert from B
query = """CREATE TABLE C(id dtype, col2 dtype);"""
c.execute(query)

## insert table B into table C
query = """INSERT INTO C SELECT id col2 FROM db2.B;"""
c.execute(query)

## detach db2
query = """DETACH db2"""
c.execute(query)

# now merge tables A and C as usual
query = """
CREATE TABLE AC AS
    SELECT  id,col2 FROM A INNER JOIN C
    ON A.id =  C.id;
"""

c.execute(query)
c.commit()

使用附加表的原始方法卡住了,而将表 B(300,000,000 x 180)插入 db1 大约需要 5 分钟,然后表 A 与表 C 的合并只用了不到 1 分钟。

【讨论】:

    【解决方案2】:

    首先执行此操作以查看生成的表有多大:

    select count(*) 
    from A INNER JOIN db2.B
    ON A.id = db2.B.id
    

    我怀疑您的联接将这些表增加了太多。

    如果结果表太大,我们想知道为什么。

    一旦我们知道桌子有多大,我们就可以计算出需要多长时间。

    最后,我会监控数据库以查看它正在取得进展。是不是越来越大了?您开始使用 SWAP 了吗?

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-06-20
      相关资源
      最近更新 更多