bigywater.tech
Django · 58

Migration Squashing

迁移文件积累到几百个,新环境 migrate 很慢。squashmigrations 能压缩它们,但已经部署的库怎么办?这篇把「新旧迁移共存」时的三种状态都验证一遍。

5 → 1
squashmigrations 把 5 个迁移优化成 1 个 CreateModel 操作
replaces
合并迁移用 replaces 声明它替代哪些迁移
共存
全新库走合并迁移;已经应用了旧迁移(部分)的库继续走旧迁移

原始迁移

实测 · 本机执行输出
  0001_initial: ['CreateModel']
  0002_p_a: ['AddField']
  0003_p_b: ['AddField']
  0004_alter_p_name: ['AlterField']
  0005_p_c: ['AddField']

五个迁移,每个操作都很小。

合并

实测 · 本机执行输出
  Will squash the following migrations:
   - 0001_initial
   - 0002_p_a
   - 0003_p_b
   - 0004_alter_p_name
   - 0005_p_c
  Optimizing...
    Optimized from 5 operations to 1 operations.
  Created new squashed migration <实验目录>
    You should commit this migration but leave the old ones in place;
    the new migration will be used for new installs. Once you are sure
    all instances of the codebase have applied the migrations you squashed,
    you can delete them.
  合并后的文件: 0001_initial_squashed_0005_p_c.py  操作: ['CreateModel']  replaces: [('lab','0001_initial'),('lab','0002_p_a'),('lab','0003_p_b'),('lab','0004_alter_p_name'),('lab','0005_p_c')]

squashmigrations app 0001 0005 生成新文件并保留旧文件。合并迁移里的 replaces 列出被替代的迁移。官方建议的流程:提交合并迁移 → 等所有环境都应用了旧迁移 → 删除旧迁移并把合并迁移的 replaces 去掉(后两步本文没有做)。

新旧共存时选哪套

实测 · 本机执行输出
  全新数据库: ['lab.0001_initial_squashed_0005_p_c']
  已经应用到 0003 之后 django_migrations: ['0001_initial', '0002_p_a', '0003_p_b']
  这时 migrate --plan: ['lab.0004_alter_p_name', 'lab.0005_p_c']
  全部 migrate 之后 django_migrations: ['0001_initial', '0002_p_a', '0003_p_b', '0004_alter_p_name', '0005_p_c', '0001_initial_squashed_0005_p_c']
  再 migrate --plan: (无事可做)

规则(实测):如果 replaces 里的迁移在数据库里要么全部应用要么全部没应用,就用合并迁移;部分应用则用旧迁移,直到全部应用后 Django 会补一条合并迁移自己的记录。

收益

实测 · 本机执行输出
  SQL 语句数:五个旧迁移合计 17 条;合并后的 0001_initial_squashed_0005_p_c 1 条

SQL 条数是 SQLite 上的(它对每次改列都重建表),PostgreSQL 上收益要小一些。

分步演示:压缩迁移

squashmigrations
本步的对象

    本文用到的工具与边界

    • 本机 macOS 27 / Python 3.14.7 / Django 6.1.1(默认用 SQLite,其它数据库会在文中注明),用 django.test.Client 或真实的本机服务器进程实测;计时用 time.perf_counter,数字每次运行会有小幅抖动。SQLite
    • 没有验证:合并迁移里包含 RunPython 时的处理(优化器不会跨越 RunPython)、跨 app 依赖的压缩、删除旧迁移后的行为、替换关系里「部分应用」的其它变体
    京ICP备2026067502号-1京公网安备11010502063487号