【问题标题】:Truncate rows and insert new ones without introducing a service break?截断行并插入新行而不引入服务中断?
【发布时间】:2017-05-05 05:26:17
【问题描述】:

我在 PostgreSQL 9.5 数据库表中有大约 1,500,000 条记录,并且我得到了一个 CSV 文件(通过 http post 请求),其中包含新的约 1,500,000 行,其中一些未更改,一些不同,还有一些已删除与原始行相比。

然后

  1. 截断旧表
  2. 循环遍历 CSV 文件的行
  3. 将每一行插入表格中

我需要一种方法来做到这一点, 不会向我的客户引入服务中断,即服务应该继续使用旧数据,直到完成所有三个步骤。目前,服务中断时间约为 1 小时,这是读取 CSV 并插入所有新行所需的时间。如果需要,我可以休息 5 分钟。

我怎样才能实现这样的行为?

这是我的 Python 脚本的缩短版本:

cursor = conn.cursor(cursor_factory=DictCursor)
cursor.execute('TRUNCATE TABLE rows CASCADE')
with open(request.files.csv) as csv_file:
    for line in csv_file:
        row = parse_line(line)
        cursor.execute(
            '''INSERT INTO rows (name, bla, blu)
            VALUES (%(name)s, %(bla)s, %(blu)s)''',
            row,
        )
cursor.commit()

【问题讨论】:

    标签: python sql postgresql psycopg2


    【解决方案1】:
    1. 使用 COPY 而不是 with open(request.files.csv),因为 1,500,000 行会在几秒钟内从 CSV 复制到表中
    2. 如果这些秒数(假设一分钟)太长,仅使用事务将无济于事,导致 truncate requires lock 在表上,而不是行上

    TRUNCATE 在它操作的每个表上获取一个 ACCESS EXCLUSIVE 锁 开

    因此,如果您可以重建表上的所有依赖对象,那么最好的可能是:

    create t_table as select * from "rows" where false;
    copy t_table from request.files.csv;
    --build all needed dependant objects (indexes, constraints,triggers);
    begin;
      alter table "rows" rename to "some_name";
      alter table "t_table " rename to "rows";
    end;
    --here is a miliseconds glitch to swith for users (if you use memcache or so - need to refresh it)
    drop table "some_name";
    

    更新 to copy columns from csv to several table columns list columns:

    复制表名 [ ( 列名 [, ...] ) ]

    【讨论】:

    • 在 truncate 命令出现问题之前,截断会影响正在使用快照的其他事务,因此无论如何它都不符合the service should keep using the old data until all three steps are done 的要求。
    • 这看起来很棒,谢谢!只有一个后续问题; CSV 文件有约 20 列,但我的表只需要其中的 5 列。我可以以某种方式只复制五个特定的列,还是应该在将其转发到数据库之前使用 Python 编辑 CSV?
    • @MarkusMeskanen 已更新。使用copy t_table(col1,col4,col5,etc) from request.files.csv;
    • @VaoTsun 谢谢,这对我来说都是一些非常先进的东西(就像我以前从未听说过的那样),需要做更多的研究并好好学习。你太棒了,接受了:)
    • @ŁukaszKamiński 我建议完全不截断的解决方案 - 只需删除旧表。用户将阅读原始表格,直到填写新表格
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-02-24
    • 1970-01-01
    • 2015-11-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多