mysql 在SQLAlchemy中优化包含多条记录的Update语句

gz5pxeao  于 2022-12-17  发布在  Mysql
关注(0)|答案(2)|浏览(248)

我尝试使用SQLAlchemy一次更新许多记录,但是发现它非常慢。有没有最佳的方法来执行这个操作?
作为参考,我正在对40,000条记录执行更新,大约花了1个小时。
下面是我正在使用的代码。table_name 指的是加载的表,column 是要更新的单列,pairs 指的是列的主键和新值。

def update_records(table_name, column, pairs):
    table = Table(table_name, db.MetaData, autoload=True, 
    autoload_with=db.engine)
    conn = db.engine.connect()

    values = []

    for id, value in pairs:
        values.append({'row_id': id, 'match_value': str(value)})

    stmt = table.update().where(table.c.id == bindparam('row_id')).values({column: bindparam('match_value')})
    conn.execute(stmt, values)
bkhjykvo

bkhjykvo1#

将一个参数列表传递给execute()实际上会发出40k个单独的UPDATE语句,这将产生很大的开销。解决这个问题的方法是增加每个查询的行数。对于MySQL,这意味着插入到一个临时表中,然后进行更新:

# assuming temp table already created
conn.execute(temp_table.insert().values(values))
conn.execute(table.update().values({column: temp_table.c.match_value})
                           .where(table.c.id == temp_table.c.row_id))

或者,您可以使用INSERT ... ON DUPLICATE KEY UPDATE来避免创建临时表,但是SQLAlchemy本身并不支持这一点,因此您需要使用一个定制的编译构造(例如this gist)。

pw136qt2

pw136qt22#

根据文档fast-execution-helpers,批量更新语句可以作为一条语句发布,在我的实验中,这个技巧将更新或删除时间从30分钟减少到1分钟。

engine = create_engine(
    "postgresql+psycopg2://scott:tiger@host/dbname",
    executemany_mode='values_plus_batch',
    executemany_values_page_size=5000, executemany_batch_page_size=5000)

相关问题