关系型数据库(引擎无关)
概述
引擎无关的关系型数据库最佳实践。原则与模式一次性编写;仅在 SQL 方言差异(MSSQL vs MySQL/MariaDB)之处内联标记或收集在方言速查表中。以正确性和基于测量证据的最小变更作为优化目标。
使用时机
- 设计或审查模式(表、键、规范化、数据类型)。
- 添加或修复索引;诊断慢查询或全表扫描。
- 读取执行计划以找出瓶颈。
- 选择或排查事务隔离、锁定或死锁。
- 对大型结果集进行分页;消除 N+1 访问。
- 规划生产安全的模式迁移。
不适用于: 引擎内部深入探讨(如 InnoDB 缓冲池等存储引擎内部机制、仅限某厂商的特性、仅限 T-SQL 的构造、复制/分片拓扑)。请使用该引擎自身的文档或专用的单引擎技能。
工作流程
- 首先建立上下文。 哪个引擎 + 哪个主要版本?读写比例、行数、延迟目标、OLTP 还是分析型。建议会因这些因素而变化。
- 仅阅读以下每个章节中链接的相关参考文档。
- 提出能解决问题的最小变更,并说明其权衡。
- 用证据验证——捕获变更前后的执行计划以及行数/时间指标(参见
references/execution-plans.md),而不是仅凭经验法则。 - 对于生产环境,需包含回滚计划及部署后的验证。
模式设计
- 显式建模关系;从规范化(3NF/BCNF)开始,只有在有测量依据的情况下才进行反规范化。每个表都需要一个稳定的主键。
- 选择最窄的正确数据类型;在模式层面(NOT NULL、UNIQUE、CHECK、FK)约束无效状态,而不是仅在应用代码中处理。
索引
- 对
WHERE、JOIN和ORDER BY中使用的列建立索引——依据选择性,而非猜测。复合索引顺序:等值列在前,范围/排序列在后(最左前缀规则)。范围谓词会阻止后续列使用索引。 - 覆盖索引可避免表查找。审计并删除未使用或重复的索引;每个索引都会增加写操作的成本。
查询优化
- 保持谓词 SARGable——不要在
WHERE中对索引列使用函数/隐式类型转换。仅选择需要的列。优先使用EXISTS而非IN (子查询),当不需要去重时使用UNION ALL而非UNION,并对大型写操作进行批量处理。 - 使用键集(游标)分页替代大型
OFFSET。通过批处理或连接消除 N+1 问题。
事务与锁定
- 保持事务简短;在事务外执行 I/O 和慢速工作。以一致顺序访问行以避免死锁;预期可能发生死锁并采用退避重试。
- 了解您的引擎的默认隔离级别(各引擎不同)以及每个级别允许的异常。有目的地使用锁定读(
FOR UPDATE),而不是出于习惯。
迁移与 DDL
- 进行模式变更时应遵循“先扩展 → 回填 → 收缩”的渐进式且向后兼容的方式。大型/锁表型 DDL 需要在线策略和回滚路径。
参考: 迁移与 DDL
引擎方言差异
自增列、标识符引用、分页、Upsert、字符串函数、当前时间、EXPLAIN 和默认隔离级别在不同引擎间均有差异。在编写可移植 SQL 之前,请确认目标引擎的语法。
参考: 引擎方言速查表
安全护栏
- 优先使用测量证据(执行计划、指标)而非泛泛规则。
- 当行为依赖于特定引擎时,请明确说明引擎和主要版本。
- 在进行破坏性操作(DROP/DELETE/TRUNCATE 或任何不可逆迁移)前,必须获得明确的人类审批。始终确保已确认存在备份。