【问题标题】:How to efficiently UPDATE a column in a large PostgreSQL table using Python / psycopg2?如何使用 Python / psycopg2 有效地更新大型 PostgreSQL 表中的列?
【发布时间】:2015-10-21 10:03:01
【问题描述】:

我有一张大桌子。 PostgreSQL 9.4 数据库中有 1000 万行。它看起来有点像这样:

gid | number1 | random | result | ...
 1  |    2    |  NULL  |  NULL  | ...
 2  |   15    |  NULL  |  NULL  | ...
... |   ...   |   ...  |  ...   | ...

现在我想将random 和result 列更新为number1 的函数。这意味着至少需要在数据库外部的脚本中生成random。由于我的内存有限,我想知道如何使用psycopg2 有效地做到这一点。我相信我面临两个问题:如何在不使用太多 RAM 的情况下获取数据以及如何将其放回那里。 simpleton 方法如下所示:

curs.execute("""SELECT gid1, number1 FROM my_table;""")
data = curs.fetchall()

result = []
for i in data:
    result.append((create_random(i[1]), i[0]))
curs.executemany("""UPDATE my_table
                    SET random = %s
                    WHERE gid = %s;""",
                 results)
curs.execute("""UPDATE my_table
                SET result = number1 * random;""")

但是,这肯定会很快耗尽我所有的记忆,并永远占用UPDATE my_table。

什么是更明智的策略?数据库正在被独占访问并且可以被锁定。不幸的是,PostgreSQL 随机函数不适合我的情况。

【问题讨论】:

  • 定义“to much RAM”,因为 1000 万 * 3 个整数是 240MB,这对于许多系统来说是可以管理的。另外,您的生成逻辑可以实现为存储过程吗?
  • 你可以使用 (PL/Python)[postgresql.org/docs/9.4/static/plpython.html]?如果是这样,您可以编写自己的替代 Postgres 的随机函数,并将其作为一个 UPDATE 语句在数据库中运行。
  • @foz 哦 - 有趣!但我认为这在我的情况下不起作用,因为我需要 numpy 包......?
  • @n1000 好吧,我自己没有尝试过,但是这里有一个在 PL/Python 函数中导入 numpy 的示例:github.com/ihuston/plpython_examples/blob/master/…

标签: python postgresql sql-update psycopg2


【解决方案1】:

unnest 一次性完成所有数据:

def create_random(i):
    return random() * i

curs.execute("select gid, number from t;")
data = curs.fetchall()

results = []
for i in data:
    results.append((create_random(i[1]), i[0]))

curs.execute("""
    update t
    set
        rnd = s.rnd,
        result = number * s.rnd
    from unnest(%s) s(rnd numeric, gid integer)
    where t.gid = s.gid;
""", (results,))

con.commit()

表 t:

create table t (
    gid integer,
    number integer,
    rnd float,
    result float
);

【讨论】:

  • 哇 - UPDATE 比使用 executemany 快 500%。谢谢!因此,您认为将所有内容提取到 RAM 并使用 unnest 将其放回原处可以吗?我只是担心我可能会用完更大的表和更多列的 RAM。不需要命名游标或类似的东西?
  • @n1000 只要您认为可以进行客户端/服务器往返,就可以了。 PL/Python 函数比处理游标和客户端/服务器往返更简单。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2017-12-01
  • 1970-01-01
  • 2017-01-04
  • 1970-01-01
  • 2017-06-12
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多