该给字段加索引当且仅当它高频出现在where、order by或group by中;区分度低(如is_deleted)或范围查询后列不宜单独建索引;联合索引需按使用顺序设计,并用explain验证命中效果。

什么时候该给字段加索引?看查询条件和排序分组
索引不是越多越好,而是为高频、高代价的查询“减负”。如果你的 WHERE 条件里总出现 user_id、status 或 created_at,或者经常用它们做 ORDER BY / GROUP BY,这些就是优先候选。
反例:给 is_deleted(只有 0/1)单独建索引,MySQL 很可能直接忽略它——区分度太低,优化器认为全表扫描更快。
- 单列索引适合等值查询(
=、IN)或范围查询(BETWEEN、>=),但范围之后的列无法走索引 - 联合索引要注意字段顺序:
INDEX (a, b, c)能加速WHERE a=1 AND b=2,但对WHERE b=2无效 - 用
EXPLAIN看type是否为ref或range,key是否命中你建的索引
TEXT/VARCHAR 长度怎么定?别盲目设 255 或 65535
MySQL 的 VARCHAR 实际存储开销 = 内容长度 + 1~2 字节长度头;TEXT 类型则强制走溢出页,访问更慢。选型核心是「够用且留余量」,不是越大越安全。
- 用户名、邮箱、手机号:用
VARCHAR(64)足够(UTF8MB4 下 64 字符最多占 256 字节) - 标题类字段:
VARCHAR(255)是常见选择,但若业务明确最长 120 字,就写VARCHAR(120)—— 更小的字段利于索引缓存和排序性能 - 避免
TEXT除非真要存长文本;如果只是偶尔超长,可考虑VARCHAR(1000)+ 应用层截断提醒 -
ENUM表面省空间,但增删值要 DDL,线上改表风险高,不如用TINYINT+ 注释说明取值含义
时间字段用 DATETIME 还是 TIMESTAMP?看时区和年份需求
两者都存时间,但行为差异很大:TIMESTAMP 自动转时区、范围小(1970–2038)、受 MySQL 时区变量影响;DATETIME 是纯字面值,不转换,范围大(1000–9999),推荐新项目默认用它。
- 需要自动记录创建/更新时间?用
DATETIME DEFAULT CURRENT_TIMESTAMP(MySQL 5.6+ 支持) - 跨时区业务(如全球化后台)必须用
DATETIME,否则TIMESTAMP在不同连接时区下读出来的时间会变 -
TIMESTAMP占 4 字节,DATETIME占 5 字节(5.6.4+),空间差距微乎其微,别为这省字节牺牲可维护性 - 如果字段要参与索引且常用于范围查询(比如查最近 7 天订单),
DATETIME更稳定,不受时区设置干扰
NULL 值要不要允许?多数时候设 NOT NULL 更省心
允许 NULL 会让字段多占 1 位空标志位,更重要的是增加查询复杂度:任何涉及该字段的比较(=、!=、IN)都得额外处理 IS NULL 分支,索引也可能失效。
- 数字类字段:用
0或-1代替NULL(比如score默认 0,比NULL更易统计) - 字符串字段:空字符串
''比NULL更直观,也避免 ORM 映射歧义 - 真有“未知”语义?比如用户未填写生日,可以接受
NULL,但要在应用层显式判断,不能依赖数据库隐式行为 -
NOT NULL字段在覆盖索引(Covering Index)中更容易被优化器选中,减少回表次数
索引和类型不是一次性拍板的事,上线后得盯着慢查询日志和 SHOW INDEX FROM table_name 的实际使用率。最常被忽略的是联合索引的字段顺序和前缀长度——一个 VARCHAR(500) 字段只用前 20 字符就能区分 99% 的值,那建索引时加个 (content(20)) 就能省下一大半空间和内存。











