PHP不设计表结构,质量取决于CREATE TABLE语句:字段类型须精准匹配(如手机号用VARCHAR(11)、金额用DECIMAL(10,2))、索引按WHERE条件合理设计、外键与约束由数据库强制保障、大字段冷数据拆分、字符集统一utf8mb4。

PHP 本身不设计表结构,它只是执行 SQL 命令的载体;真正决定质量的是你写的 CREATE TABLE 语句是否贴合业务、可维护、能扛住增长。别等写完控制器再补表,字段加错、类型选歪、索引漏建,后期改起来比重写逻辑还疼。
字段类型不是“差不多就行”,而是按场景硬匹配
用错类型是高频隐形坑:比如把手机号存成 INT,遇到带 0 开头(如 0912345678)就直接截断;用 FLOAT 存金额,算账时出现 0.1 + 0.2 = 0.30000000000000004 这种问题。
- 手机号、身份证号、订单号这类“看起来像数字但不参与计算”的字段,一律用
VARCHAR,长度按实际最大值设(如手机号VARCHAR(11)) - 金额必须用
DECIMAL(10,2),别信FLOAT或DOUBLE的精度宣传 - 时间统一用
DATETIME,除非你真有跨语言毫秒对齐需求,否则别用INT存时间戳——CURRENT_TIMESTAMP和时区支持更省心 -
TEXT字段不能直接建普通索引,要加前缀:INDEX idx_title (title(191))(utf8mb4 下 191 是安全上限)
索引不是“查得快就加”,而是看 WHERE 条件怎么写
联合索引 (user_id, status, created_at) 看似全能,但只查 created_at 时完全用不上,MySQL 无法跳过前导列。
- 高频查询条件字段必须进索引,且顺序按
WHERE中的出现优先级排(等值条件放前,范围条件放后) -
LIKE '%关键词'、!=、OR多字段无统一前导列时,索引大概率失效 - 频繁更新的字段(如阅读数、点赞数)别建索引,写入性能会明显下降
- 单字段索引和联合索引别重复建,
(a, b)已覆盖a的查询,再单独建INDEX idx_a (a)是冗余
外键和约束别全甩给 PHP 校验
数据库该拦的错误,就别等 PHP 层发现再报——用户提交邮箱重复,PHP 返回 “邮箱已被注册” 没问题;但要是数据库没设 UNIQUE,靠 PHP 先查再插,高并发下照样撞出两条重复数据。
立即学习“PHP免费学习笔记(深入)”;
- 邮箱字段加
UNIQUE+CHECK (email REGEXP '^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}$')(MySQL 8.0.16+ 支持) - 状态字段用
TINYINT(1)或ENUM('pending','paid','shipped'),并设DEFAULT 'pending' - 创建/更新时间用
created_at DATETIME DEFAULT CURRENT_TIMESTAMP和updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,PHP 插入时不用手动填 - 外键必须配
ON DELETE CASCADE或ON DELETE SET NULL,避免孤儿数据
大字段和冷数据必须拆出去
一张 articles 表里塞 content TEXT + images JSON + seo_meta TEXT,哪怕只查标题列表,也要加载几 MB 内容,IO 和内存都吃紧。
- 把访问频次低、体积大的字段(如文章正文、商品详情图、用户隐私信息)移到扩展表,用主表
id关联 - 历史订单、日志类数据按月分区,如
orders_202401、orders_202402,配合定时任务归档 - 用户表里别堆“籍贯”“兴趣标签”“紧急联系人”这种非核心字段,业务不用就别加——表越瘦,JOIN 越快,备份越小
最常被忽略的一点:字符集必须显式声明为 utf8mb4,否则 emoji、生僻字入库变问号,而且这个设置要在建库、建表、连接三处同时生效,缺一不可。



















