# Database Rules

## 来源

本规则由企业原始规范整理而来，当前仓库以本文件作为可执行口径，不再依赖 `规范合集/` 目录作为生效范围。

## 建表规约

- 表达“是/否”的字段使用 `is_xxx` 命名，类型使用 `tinyint unsigned`。
- 表名、字段名使用小写字母或数字，不使用复数名词，不使用保留字。
- 索引命名统一为 `pk_字段名`、`uk_字段名`、`idx_字段名`。
- 小数统一使用 `decimal`，禁止使用 `float`、`double`。
- 定长字符串优先 `char`；`varchar` 长度不超过 `5000`，更长文本拆表并用主键关联。
- 表必须具备 `id`、`biz_id`、`create_time`、`create_by`、`update_time`、`update_by` 六类基础字段。
- 默认使用 `InnoDB`；单表建议控制在 `500 万` 行内，`1000 万` 视为硬风险，需归档或拆分。
- 避免 `TEXT` / `BLOB`、图片、文件直接落库；字段过多时做垂直拆分。

## 索引与查询

- 业务唯一字段必须建唯一索引，组合唯一也不能只靠应用层兜底。
- 超过三表禁止 `join`；关联字段必须类型一致且建立索引。
- `varchar` 建索引必须评估前缀长度；页面查询禁止左模糊或全模糊，复杂搜索走搜索引擎。
- 组合索引优先保证等值条件在前、区分度高的列靠左，同时兼顾 `order by` 的有序性。
- `explain` 至少达到 `range`，目标达到 `ref / const`；避免隐式类型转换导致索引失效。

## SQL 语句

- 行数统计使用 `count(*)`；聚合求和注意 `IFNULL(SUM(...), 0)`，避免空值导致 NPE。
- 判空使用 `ISNULL()` 或 `is null / is not null` 语义化写法，不直接用 `= null`。
- 分页场景在 `count = 0` 时直接返回，不再执行后续分页 SQL。
- 禁止外键、级联、存储过程；数据订正前先 `select` 再执行 `update / delete`。
- 多表查询、更新、删除时，列名前必须加表别名。
- `IN` 集合默认控制在 `1000` 个以内。
- 数据删除使用软删除，禁止物理删除。
- `select` 禁止使用 `*`。

## ORM 映射

- 查询字段显式列出，不依赖 `*` 与隐式映射。
- 数据库字段的 `is_xxx` 与 POJO 布尔属性通过映射层对齐，不在 Java 属性上直接保留 `is` 前缀。
- MyBatis / iBatis 使用 `resultMap` 与 `#{}`，避免 `${}` 注入风险。
- 查询结果不要直接返回 `HashMap / Hashtable` 作为长期稳定契约。
- 更新语句只更新发生变化的字段，并同步刷新 `update_time`。
- 事务不要滥用；使用事务时同步考虑缓存、搜索、消息、统计等外围回滚或补偿。
