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

如何在Django中按条件高效批量删除重复数据?

处理2600万行数据的重复删除方案

一、Django ORM实现(可行但性能受限)

Django ORM确实能实现需求,但面对2600万行的超大表,直接全量操作会有明显性能瓶颈,建议分批次执行:

实现步骤

  1. 先查询每组(share_class__id + date)中需保留的记录ID:
from django.db.models import Max, Subquery, OuterRef

# 子查询获取每个分组最新updated对应的记录ID
latest_group_ids = MyModel.objects.filter(
    share_class__id=OuterRef('share_class__id'),
    date=OuterRef('date')
).values('share_class__id', 'date').annotate(
    max_updated=Max('updated')
).values('id')

# 提取所有需保留的ID集合
keep_ids = MyModel.objects.filter(id__in=Subquery(latest_group_ids)).values_list('id', flat=True)
  1. 分批次删除非保留记录:
batch_size = 10000
total_deleted = 0

while True:
    # 每次获取一批待删除的ID
    delete_ids = list(MyModel.objects.exclude(id__in=keep_ids)[:batch_size].values_list('id', flat=True))
    if not delete_ids:
        break
    # 执行删除
    deleted, _ = MyModel.objects.filter(id__in=delete_ids).delete()
    total_deleted += deleted
    print(f"已删除 {total_deleted} 条重复数据")

注意:此方式会生成超大的keep_ids集合,占用大量应用层内存,且循环批次多,整体执行效率偏低,仅适合小批量数据场景。

二、原生SQL实现(高效推荐)

针对2600万行的超大表,原生SQL配合窗口函数是最优解——直接在数据库层面处理,避免大量数据传输到应用层,性能提升显著。

PostgreSQL 写法

WITH ranked_records AS (
    SELECT 
        id,
        ROW_NUMBER() OVER (
            PARTITION BY share_class__id, date 
            ORDER BY updated DESC
        ) AS rn
    FROM myapp_mymodel  -- 替换为你的实际表名(格式:app名_模型名小写)
)
DELETE FROM myapp_mymodel
WHERE id IN (SELECT id FROM ranked_records WHERE rn > 1);

MySQL 8.0+ 写法

WITH ranked_records AS (
    SELECT 
        id,
        ROW_NUMBER() OVER (
            PARTITION BY share_class__id, date 
            ORDER BY updated DESC
        ) AS rn
    FROM myapp_mymodel
)
DELETE FROM myapp_mymodel
USING myapp_mymodel
JOIN ranked_records ON myapp_mymodel.id = ranked_records.id
WHERE ranked_records.rn > 1;

关键优化建议

  1. 备份数据:执行删除前务必全量备份,避免不可逆损失。
  2. 添加索引:提前创建复合索引加速分组排序:
    CREATE INDEX idx_share_date_updated ON myapp_mymodel(share_class__id, date, updated DESC);
    
  3. 分段处理:若单条SQL执行超时,可按date分段,比如按月份拆分执行删除逻辑。

总结

  • 小批量数据用Django ORM即可满足需求;但2600万行的超大表场景,原生SQL是唯一高效的选择,能规避应用层内存压力和数据传输开销。
  • 无论采用哪种方案,优先添加合适的索引是提升性能的核心。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.10 04:07:36