You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Django批量更新JSONField字段键名 320万条记录提速方案咨询

批量更新JSON字段键名优化方案

注:以下方案基于PostgreSQL数据库,若使用MySQL,可替换为JSON_REMOVE、JSON_SET等对应JSON操作函数实现相同逻辑。

方案1:Django ORM 原生实现(无数据往返Python开销)

该方案完全在数据库层面执行操作,避免了循环拉取数据、序列化、单条save的高额IO开销,320万条数据通常几分钟即可执行完成,性能是Python循环方案的百倍以上。

from django.db.models import F, Func, Value

MyModel.objects.filter(
    # 只处理存在旧键的记录
    stats__has_key="my_old_key"
).exclude(
    # 跳过已经存在新键的记录
    stats__has_key="my_new_key"
).update(
    stats=Func(
        # 第一步:新增my_new_key,值复用原my_old_key的值
        Func(
            F("stats"),
            Value("my_new_key"),
            F("stats__my_old_key"),
            function="jsonb_set"
        ),
        # 第二步:删除旧键my_old_key
        Value("my_old_key"),
        function="-"
    )
)

方案2:直接执行原生SQL

如果需要更灵活的控制,可直接执行以下SQL,既可以在数据库客户端直接运行,也可以通过Django的cursor调用:

UPDATE myapp_mymodel
SET stats = (stats - 'my_old_key') || jsonb_build_object('my_new_key', stats->'my_old_key')
WHERE stats ? 'my_old_key' AND NOT stats ? 'my_new_key';

对应Django调用代码:

from django.db import connection

with connection.cursor() as cursor:
    cursor.execute("""
        UPDATE myapp_mymodel
        SET stats = (stats - 'my_old_key') || jsonb_build_object('my_new_key', stats->'my_old_key')
        WHERE stats ? 'my_old_key' AND NOT stats ? 'my_new_key';
    """)

额外优化建议

  • 执行前可先给stats字段建GIN索引,大幅提升过滤速度,建索引语句:CREATE INDEX idx_mymodel_stats_gin ON myapp_mymodel USING GIN(stats);
  • 如果是线上业务怕一次性锁表影响服务,可在WHERE条件中增加主键范围分段执行,比如每次处理10万条,分批次提交避免长事务。
  • 全量执行前建议先筛选少量数据验证逻辑正确性,避免误操作。

内容的提问来源于stack exchange,提问作者Revinder

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.03 17:27:03