← ClaudeAtlas

database-safetylisted

写 SQL、改表结构、做数据迁移时使用。防止锁表、丢数据、慢查询。
Wade-DevCode/awesome-coding-skills-cn · ★ 3 · Data & Documents · score 78
Install: claude install-skill Wade-DevCode/awesome-coding-skills-cn
# 数据库安全 ## 何时用 - 新增或修改数据库迁移脚本(migration),上线前评估影响时。 - 写查询逻辑,需要确认性能是否可接受、是否存在 N+1 时。 - 写更新/删除语句,操作生产数据或批量变更前。 - 遇到慢查询告警、锁等待、数据库 CPU 飙高时定位根因。 ## 核心规则 ### 1. 迁移可回滚,大表结构变更用在线 DDL **规则:** 每个 migration 必须配 `down` 方法(回滚路径);对行数超过百万的表加列或建索引,必须评估锁表风险,使用在线 DDL 工具(`pt-online-schema-change`、`gh-ost` 或数据库自带的 `ALGORITHM=INPLACE`)而非直接 `ALTER TABLE`。 **为什么:** AI 生成迁移脚本时几乎从不写 `down`——"反正一般不需要回滚"。但生产故障时那个"一般"就变成了"现在":新代码引发 panic,需要立刻回滚版本,却发现数据库结构已经变了,应用旧版本��不起来,只能手动改表,在最紧张的时候操作最危险的事。大表直接 `ALTER TABLE ADD COLUMN` 在 MySQL 5.x 上会持有表级写锁,百万行意味着分钟级锁表,期间所有写操作排队,直接触发超时告警。 **怎么做:** - 框架约定(Flyway/Liquibase/Alembic/Rails migrations)每个文件都要有回滚逻辑,CI 跑 `migrate up` 后紧接着跑 `migrate down` 再 `migrate up`,验证回滚可用。 - 估算表行数:`SELECT COUNT(*)` 或查 `information_schema`;超过 50 万行的表结构变更,方案里必须写明用哪种在线 DDL。 - 建索引用 `CREATE INDEX CONCURRENTLY`(PostgreSQL)或 `ALTER TABLE ... ALGORITHM=INPLACE, LOCK=NONE`(MySQL 8+),不阻塞读写。 --- ### 2. 禁止在循环里查库,用批量/JOIN/预加载 **规则:** 任何"先取列表,再对每条记录发一次查询"的模式都是 N+1,必须改为一次批量查询或 JOIN。 **为什么:** AI 生成 ORM 代码时,N+1 是最高频的性能 bug,而且在小数据集的本地环境下完全感觉不到——10 条记录发 11 次查询,每次 1 ms,总耗时 11 ms,"挺快的"。到了生产环境 1000 条记录,就变成 1001 次查询,慢查询日志被打爆,数据库连接池耗尽,整个服务开始抖动。这类问题在代码 review 时也容易被忽略,因为"逻辑上没错"。 **怎么做:** ```python # 反例:N+1 orders = Order.query.all() for order in orders: user = User.query.get(order.user_id) # ❌ 每次循环一次查询 print(user.name) # 正例:预加载 / 批量查询 orders = Order.query.options(joinedload(Order.user)).all() # ✅ 一次 JOIN # 或者 user_ids = [o.user_id for o in orders] users = {u.id: u for u in User.query.filter(Use