← 中文资源

简体中文版本

Drizzle 迁移与结构演进

用 Drizzle 管理 PostgreSQL 结构演进:增量迁移按加列、回填、收紧约束三步走,配套索引与生成式 SQL 审查链路。

阅读英文原文

示例说明

线上加列直接 NOT NULL 会锁表并拒绝已有行,标准做法是三段式:先加可空列让写入路径兼容,再按业务规则回填历史数据,最后收紧非空约束。Drizzle 的 sql 模板让手写步骤与类型安全表定义共存,drizzle-kit generate 还能从 schema 差异自动生成迁移文件供评审。

技术要点

  • 可空先行避免锁表与写失败
  • 回填单独成步可控可重跑
  • 收紧约束前数据已完整

代码解读

三个 sql 片段对应三步:加列无默认不重写历史行;回填把到期日设为创建日加三十天并限定 NULL 条件支持幂等重跑;最后 ALTER 设非空并补索引。applySteps 顺序执行后追加索引创建,IF NOT NULL 兜底重复执行。

使用建议

大表回填要分批提交控制事务大小与锁窗口。迁移文件进版本库并禁止手改已执行过的历史。收紧约束前用检查查询确认无残留 NULL。

代码示例

import { pgTable, text, integer, timestamp, index } from 'drizzle-orm/pg-core';
import { sql } from 'drizzle-orm';

// 初始 schema(drizzle/0000_init.sql 由 drizzle-kit generate 产出)
const invoices = pgTable('invoices', {
  id: integer('id').primaryKey(),
  customer: text('customer').notNull(),
  createdAt: timestamp('created_at').defaultNow(),
});

// 增量迁移:新增可空列 → 回填 → 收紧约束
const ADD_COLUMN = sql`
  ALTER TABLE invoices
    ADD COLUMN due_date timestamp;
`;

const BACKFILL = sql`
  UPDATE invoices
    SET due_date = created_at + interval '30 days'
    WHERE due_date IS NULL;
`;

const TIGHTEN = sql`
  ALTER TABLE invoices
    ALTER COLUMN due_date SET NOT NULL;
`;

async function applySteps(db, steps: ReturnType<typeof sql>[]) {
  for (const step of steps) {
    await db.execute(step);
  }
  await db.execute(sql`
    CREATE INDEX IF NOT EXISTS invoices_due_date_idx
      ON invoices (due_date);
  `);
}

console.log('three-step migration prepared: add, backfill, tighten');