一、前言

上一篇
SQL 第一篇:CRUD 实战,从 user 表开始写接口
我们已经完成了 CRUD。

但是你会发现一个问题:

用户的信息越来越多

比如:

  • 用户名
  • 密码
  • 手机号
  • 邮箱
  • 性别
  • 生日
  • 收货地址
  • 默认地址
  • 省市区

这时候很多初学者会这样干:

全部塞进 user 表

最后 user 表会越来越臃肿。

所以这一篇,我们正式进入:

❗ 表结构设计(建模)

这一步,才是真正开始接近企业开发。

二、企业为什么不能只用一张 user 表?

很多人最开始会这样设计:

CREATE TABLE user (
    id BIGINT PRIMARY KEY AUTO_INCREMENT,
    username VARCHAR(64),
    password VARCHAR(128),
    phone VARCHAR(20),
    email VARCHAR(100),
    real_name VARCHAR(50),
    province VARCHAR(50),
    city VARCHAR(50),
    detail_address VARCHAR(200)
);

看起来没问题。

但实际上:

账号信息
用户资料
收货地址

是三种完全不同的数据。

三、企业里的真实做法:拆表

所以企业里通常会拆成:

user            用户主表
user_detail     用户详情表
user_address    用户地址表

这样设计后:

  • 结构更清晰
  • 更容易扩展
  • 更符合业务划分
  • 查询性能更稳定

四、第一张表:user(用户主表)

1. 建表语句

CREATE TABLE user (
    id BIGINT PRIMARY KEY AUTO_INCREMENT COMMENT '主键ID',

    username VARCHAR(64) NOT NULL UNIQUE COMMENT '用户名',

    password VARCHAR(128) NOT NULL COMMENT '密码',

    create_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',

    update_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP
    ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间'
);

2. 这张表存什么?

这一张表只存:

登录相关信息

比如:

  • 用户名
  • 密码
  • 时间

它是:

账号体系核心表

五、重点字段讲解(企业必须懂)


1️⃣ id(主键)

id BIGINT PRIMARY KEY AUTO_INCREMENT

含义:

每条数据唯一标识

为什么用 BIGINT?

因为企业数据量可能很大。

INT 最大约 21 亿
BIGINT 更安全

所以很多企业直接统一:

主键默认 BIGINT

AUTO_INCREMENT 是什么?

表示:

主键自动增长

插入第一条:

id = 1

第二条:

id = 2

数据库自动维护。


六、username 为什么 UNIQUE?

username VARCHAR(64) NOT NULL UNIQUE

重点:

UNIQUE = 唯一索引

意味着:

用户名不能重复

比如:

zhangsan

只能有一个。

否则会报错。


七、password 为什么 VARCHAR(128)?

很多人会问:

密码不是123456吗?
为什么128?

因为企业里不会直接存明文密码。

而是:

加密后的字符串

比如:

BCrypt
MD5
SHA

加密后长度会很长。

所以一般:

VARCHAR(128)

甚至更大。


八、create_time 和 update_time(企业高频)


1️⃣ create_time

create_time DATETIME DEFAULT CURRENT_TIMESTAMP

表示:

数据创建时间

插入时自动生成。


2️⃣ update_time

update_time DATETIME DEFAULT CURRENT_TIMESTAMP
ON UPDATE CURRENT_TIMESTAMP

表示:

数据更新时间

每次 UPDATE 自动刷新。


九、第二张表:user_detail(用户详情表)


1. 建表语句

CREATE TABLE user_detail (

    id BIGINT PRIMARY KEY AUTO_INCREMENT COMMENT '主键ID',

    user_id BIGINT NOT NULL UNIQUE COMMENT '用户ID',

    real_name VARCHAR(50) COMMENT '真实姓名',

    phone VARCHAR(20) COMMENT '手机号',

    email VARCHAR(100) COMMENT '邮箱',

    gender TINYINT DEFAULT 0 COMMENT '性别:0-未知 1-男 2-女',

    birthday DATE COMMENT '生日',

    create_time DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',

    update_time DATETIME DEFAULT CURRENT_TIMESTAMP
    ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间'
);

十、为什么拆出 user_detail?

因为:

用户资料 ≠ 登录信息

很多业务里:

登录频率很高

但是:

用户资料很少修改

所以企业通常会拆表。


十一、这里最关键的字段:user_id

user_id BIGINT NOT NULL UNIQUE

这个字段是:

❗ user_detail 属于哪个 user


为什么 UNIQUE?

因为:

一个用户只有一份详情

所以:

user 1 —— 1 user_detail

这就叫:

一对一关系

十二、第三张表:user_address(用户地址表)


1. 建表语句

CREATE TABLE user_address (

    id BIGINT PRIMARY KEY AUTO_INCREMENT COMMENT '主键ID',

    user_id BIGINT NOT NULL COMMENT '用户ID',

    receiver_name VARCHAR(50) NOT NULL COMMENT '收货人姓名',

    phone VARCHAR(20) NOT NULL COMMENT '收货人电话',

    province VARCHAR(50) NOT NULL COMMENT '省',

    city VARCHAR(50) NOT NULL COMMENT '市',

    district VARCHAR(50) NOT NULL COMMENT '区/县',

    detail_address VARCHAR(200) COMMENT '详细地址',

    is_default TINYINT DEFAULT 0 COMMENT '是否默认:0-否 1-是',

    create_time DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',

    update_time DATETIME DEFAULT CURRENT_TIMESTAMP
    ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',

    INDEX idx_user_id (user_id)
);

十三、为什么 user_address 不加 UNIQUE?

因为:

一个用户可以有多个地址

比如:

家
公司
父母家

所以:

同一个 user_id 可以出现多次

这就是:

一对多关系

十四、为什么加索引?

INDEX idx_user_id (user_id)

因为后面经常会这样查:

SELECT * FROM user_address
WHERE user_id = 1;

所以:

user_id 是高频查询字段

企业里通常会加索引。


十五、三张表关系(核心)

最终关系:

user 和 user_detail  1对1

user 和 user_address 1对多


十六、核心

这一篇最重要的不是语法。

而是: 开始理解“为什么企业要拆表”

📌 数据库拆表规则(最终笔记版)

❗ 总原则:

一张表,只做一件事。

-----------------------------------

怎么判断一张表是不是“做了多件事”?

① 职责不同
账号、资料、地址不是一类数据。

② 出现一对多
一个用户多个地址、多个订单。

③ 字段太多
一张表几十上百字段,说明职责可能混乱。

④ 修改频率不同
高频修改字段不要影响核心主表。

⑤ 出现大字段
富文本、长内容、JSON 单独拆。

⑥ 查询场景不同
登录、用户中心、收货页关注的数据不同。

-----------------------------------

📌 最终本质:

拆表不是死记规则,而是判断:

这张表是不是还只做一件事?

-----------------------------------

📌 案例:

user
    → 账号登录

user_detail
    → 用户资料

user_address
    → 收货地址

账号 ≠ 资料 ≠ 地址

所以拆表。


十七、一句话总结

企业数据库设计,本质是:

👉 按业务职责拆表,而不是把所有字段塞进一张表。


下一篇

下一篇进入:

SQL 第三篇:表关系设计(user_id 到底是什么)

真正讲透:

一对一
一对多
外键
user_id

以及:

为什么 JOIN 能把表拼起来
Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐