适用场景:MySQL数据库表结构设计、业务表优化、动态属性存储、数据报表转换、后端开发落地
阅读目标:彻底掌握横竖表区别、建表规范、使用场景、数据互转实操、企业级设计原则,可直接用于项目开发
一、数据库表基础概念(新手必看)
在 MySQL 中,所有业务数据都以「数据表」形式存储,数据表的核心组成只有两个:行(记录)和列(字段),所有横表、竖表的设计逻辑,都基于这两个基础概念延伸。
1. 列(字段):代表数据的「属性、类别」,相当于表格的表头,比如学生姓名、语文成绩、科目、分数,固定定义数据是什么类型。
2. 行(记录):代表一条完整的「具体数据」,相当于表格的每一行内容,比如小明的所有成绩、小红的所有成绩,是真实存储的业务数据。
简单理解:列 = 数据规则(定义字段),行 = 具体数据(存储内容)。
普通数据表默认「列固定、行新增」,但根据业务灵活性需求,衍生出两种主流设计:横表(常规表)和竖表(动态扩展表)。
二、横表、竖表超详细详解(新手重点掌握)
在 MySQL 实际开发中,所有数据表只分两大类:横表(常规业务表) 、竖表(动态键值扩展表)。二者没有优劣之分,只是适用业务完全不同。下面逐一对两种表结构做零基础、超详细拆解。
2.1 横表(直表 / 宽表)------ 项目默认首选表结构
2.1.1 通俗定义
横表是 MySQL 标准、默认、最主流 的表结构。遵循「一条业务数据占一行、一个属性占一列」的规则。
简单大白话:一个对象,所有信息平铺在同一行。
比如学生对象:姓名、语文、数学、英语全部平铺成字段,一行数据就能完整描述一个学生。
2.1.2 核心结构特征(重点)
-
列(字段)固定:建表时定义好所有字段,运行过程中基本不改动
-
行(数据)新增:新增业务数据只增加行数,不增加列数
-
一行 = 一条完整业务数据
-
列多、行相对少,所以又叫宽表
2.1.3 底层优势原理(为什么查询快?)
横表所有属性在同一行,数据库查询时不需要跨行拼接数据、不需要聚合计算。
查一个学生成绩,只需要读取一行数据,IO 开销极低,支持索引、排序、筛选、关联查询、分页统计,适配所有主流业务场景。
2.1.4 横表详细优缺点
✅ 优点详细说明:
-
查询速度快:单条数据一行存储,无需多行合并
-
字段类型可控:每个字段可以单独设置 int、varchar、date 等精准类型,数据规范
-
支持索引优化:任意字段可以建索引,查询、筛选、排序性能高
-
统计简单:SUM、AVG、COUNT、分组统计直接使用,无需复杂 SQL
-
代码好写、适配前端:返回结构规整,前端直接渲染表格、列表、表单
-
事务稳定:数据集中存储,增删改事务不易出错
❌ 缺点详细说明:
-
扩展性极差:业务新增属性必须 改表结构(ALTER TABLE 加字段)
-
不适合多变业务:如果业务属性经常新增、变动,会频繁改库,风险高
-
空字段浪费空间:部分数据没有的属性,会出现大量 NULL 空字段
2.2 竖表(窄表 / 键值表 / EAV扩展表)------ 动态业务专用表
2.2.1 通俗定义
竖表是为了解决「横表无法动态扩展」而诞生的特殊表结构。遵循「字段固定不变、数据无限新增」的规则。
大白话:一个对象的每一个属性,单独占一行数据。
学生的语文成绩是一行、数学成绩是一行、英语成绩是一行,同一个学生多条数据。
2.2.2 固定通用字段(所有竖表统一标准)
所有业务的竖表,结构永远只有这 4 个核心字段,不会新增列:
-
id:主键
-
relation_id:业务主体ID(学生ID、用户ID、商品ID)
-
attr_key:属性名(字段名,如语文、颜色、尺寸、配置名)
-
attr_value:属性值(具体数据,如90、红色、XL、开启)
2.2.3 核心结构特征(重点)
-
列永久固定,永远不需要改表结构
-
新增业务属性只新增行数,零成本扩展
-
行多、列极少,所以又叫窄表
-
一条完整业务数据,被拆分为 N 行键值对存储
2.2.4 底层优势原理(为什么灵活?)
横表靠「加字段」实现扩展,竖表靠「加数据」实现扩展。
无论业务后续新增多少未知属性(新增科目、新增商品规格、新增系统配置),只需要 INSERT 一条数据,无需改动代码、无需改动表结构,适配所有动态、未知业务。
2.2.5 竖表详细优缺点
✅ 优点详细说明:
-
无限扩展能力:业务属性随便加,无需 DDL 语句、无需停服、无需改代码结构
-
适配未知业务:适合开发初期无法确定字段、字段频繁变动的场景
-
无空字段浪费:有什么属性存什么行,不会出现大量 NULL 空数据
-
统一通用结构:所有扩展属性一张表搞定,不用频繁新建数据表
❌ 缺点详细说明:
-
查询复杂:需要多行合并成一行展示,必须使用 CASE、聚合、分组
-
性能差:数据量大时多行匹配、分组合并,IO开销远大于横表
-
字段类型不可控:value 统一字符串存储,数字、日期、文本混存,无法约束类型
-
统计困难:无法直接 SUM、AVG,需要二次处理
-
代码复杂度高:后端需要手动组装数据,前端需要二次解析
2.3 横竖表核心区别(新手必背)
横表:列变要改表,数据一行存全量
竖表:列永远不改表,新增属性只加数据
| 对比维度 | 横表(宽表) | 竖表(键值表) |
|---|---|---|
| 字段结构 | 固定,建表即确定 | 永久固定,无需改动 |
| 扩展方式 | 改表加字段 | 新增数据行 |
| 查询性能 | 极高 | 较低 |
| 数据存储形式 | 一行一条完整数据 | 一条数据拆多行 |
| 适用业务 | 固定核心业务 | 动态扩展业务 |
| SQL复杂度 | 简单 | 复杂 |
-
适配未知业务:适合开发初期无法确定字段、字段频繁变动的场景
-
无空字段浪费:有什么属性存什么行,不会出现大量 NULL 空数据
-
统一通用结构:所有扩展属性一张表搞定,不用频繁新建数据表
❌ 缺点详细说明:
-
查询复杂:需要多行合并成一行展示,必须使用 CASE、聚合、分组
-
性能差:数据量大时多行匹配、分组合并,IO开销远大于横表
-
字段类型不可控:value 统一字符串存储,数字、日期、文本混存,无法约束类型
-
统计困难:无法直接 SUM、AVG,需要二次处理
-
代码复杂度高:后端需要手动组装数据,前端需要二次解析
2.3 横竖表核心区别(新手必背)
横表:列变要改表,数据一行存全量
竖表:列永远不改表,新增属性只加数据
| 对比维度 | 横表(宽表) | 竖表(键值表) |
|---|---|---|
| 字段结构 | 固定,建表即确定 | 永久固定,无需改动 |
| 扩展方式 | 改表加字段 | 新增数据行 |
| 查询性能 | 极高 | 较低 |
| 数据存储形式 | 一行一条完整数据 | 一条数据拆多行 |
| 适用业务 | 固定核心业务 | 动态扩展业务 |
| SQL复杂度 | 简单 | 复杂 |
三、统一实操案例:学生成绩管理系统(完整落地演示)
为保证通俗易懂、可落地实操,全文统一使用学生成绩业务场景,完整演示横竖表建表、存数据、数据差异。
3.1 横表设计(固定科目成绩存储)
2.1.1 建表语句(可直接执行)
sql
-- 学生成绩横表:字段固定,适配固定科目场景
CREATE TABLE score_horizontal (
id INT PRIMARY KEY AUTO_INCREMENT COMMENT '主键ID',
student_name VARCHAR(20) NOT NULL COMMENT '学生姓名',
chinese INT DEFAULT 0 COMMENT '语文成绩',
math INT DEFAULT 0 COMMENT '数学成绩',
english INT DEFAULT 0 COMMENT '英语成绩',
physics INT DEFAULT 0 COMMENT '物理成绩',
create_time DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间'
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='学生成绩横表';
2.1.2 插入测试数据(可直接执行)
sql
INSERT INTO score_horizontal (student_name,chinese,math,english,physics)
VALUES
('小明',90,85,88,92),
('小红',88,90,95,86),
('小刚',78,92,80,89);
2.1.3 横表数据结构展示
一行对应一个学生的所有成绩,结构清晰直观:
id | student_name | chinese | math | english | physics
1 | 小明 | 90 | 85 | 88 | 92
2 | 小红 | 88 | 90 | 95 | 86
2.1.4 横表优缺点
✅ 优点:结构规整、查询简单、关联查询快、适合统计报表、索引友好、数据冗余少
❌ 缺点:扩展性差,新增科目(化学、生物)必须修改表结构、新增字段,不适合动态变化的业务场景
3.2 竖表设计(动态科目成绩存储)
2.2.1 建表语句(可直接执行)
sql
-- 学生成绩竖表:字段固定,适配动态新增科目场景
CREATE TABLE score_vertical (
id INT PRIMARY KEY AUTO_INCREMENT COMMENT '主键ID',
student_name VARCHAR(20) NOT NULL COMMENT '学生姓名',
subject VARCHAR(20) NOT NULL COMMENT '科目名称(属性Key)',
score INT DEFAULT 0 COMMENT '科目成绩(属性Value)',
create_time DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间'
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='学生成绩竖表';
2.2.2 插入测试数据(可直接执行)
sql
INSERT INTO score_vertical (student_name,subject,score)
VALUES
('小明','语文',90),('小明','数学',85),('小明','英语',88),('小明','物理',92),
('小红','语文',88),('小红','数学',90),('小红','英语',95),('小红','物理',86),
('小刚','语文',78),('小刚','数学',92),('小刚','英语',80),('小刚','物理',89);
2.2.3 竖表数据结构展示
一个学生的多科成绩,拆分为多行键值对存储:
id | student_name | subject | score
1 | 小明 | 语文 | 90
2 | 小明 | 数学 | 85
3 | 小红 | 语文 | 88
2.2.4 竖表优缺点
✅ 优点:极致灵活,新增科目无需改表结构,直接插入数据即可,适配所有动态扩展属性场景
❌ 缺点:数据冗余高、查询繁琐、无法直接做快速报表统计、大数据量下查询性能较差、无法精准约束字段类型
四、横竖表数据互转实操(企业常用、可直接落地)
实际开发中,常出现竖表存数据、横表做展示的场景,以下为可直接复制执行的互转SQL,适配所有同类键值表场景。
4.1 竖表转横表(行转列,高频使用)
业务场景:动态存储成绩(竖表),前端报表、后台统计需要横向展示数据
核心原理:通过 CASE 判断匹配属性,结合 MAX 聚合去重,实现多行数据合并为一行
sql
-- 竖表转横表:行转列,统计学生各科成绩
SELECT
student_name,
MAX(CASE WHEN subject = '语文' THEN score END) AS 语文成绩,
MAX(CASE WHEN subject = '数学' THEN score END) AS 数学成绩,
MAX(CASE WHEN subject = '英语' THEN score END) AS 英语成绩,
MAX(CASE WHEN subject = '物理' THEN score END) AS 物理成绩
FROM score_vertical
GROUP BY student_name;
执行效果:自动将多行竖表数据,转为规整的横表结构,完美适配报表展示需求。
4.2 横表转竖表(列转行,低频使用)
业务场景:旧项目横表数据迁移、改造为动态竖表存储结构
核心原理:通过 UNION ALL 拆分横向字段,将单列字段转为单行键值数据
sql
-- 横表转竖表:列转行,拆分固定字段为键值对
SELECT student_name, '语文' AS subject, chinese AS score FROM score_horizontal
UNION ALL
SELECT student_name, '数学' AS subject, math AS score FROM score_horizontal
UNION ALL
SELECT student_name, '英语' AS subject, english AS score FROM score_horizontal
UNION ALL
SELECT student_name, '物理' AS subject, physics AS score FROM score_horizontal;
执行效果:将一行完整学生数据,拆分为多行科目成绩数据,适配竖表存储结构。
五、横表与竖表如何关联(新手核心必学)
真实项目中 横表永远做主表、竖表做扩展附表 ,二者不是独立使用,是主从关联关系。
很多新手疑惑:横表存主体数据、竖表存动态属性,两个表的数据怎么拼在一起?前端怎么一次性查完所有数据?本节完整讲透关联原理、关联字段、关联SQL、业务场景。
5.1 核心关联原理(最简单大白话)
横表存"主体",竖表存"主体的扩展信息"
关联唯一依据:主体ID
-
横表:拥有主体唯一ID(主键 id)
-
竖表:拥有关联字段 relation_id
规则:竖表的 relation_id = 横表的主键id,两张表就完美关联。
5.2 标准关联结构(企业统一规范)
以「学生主体 + 学生拓展成绩」为例:
横表(学生主表)------ 主体数据
student_main(id、姓名、性别、班级)
id = 学生唯一身份标识
竖表(学生拓展属性表)------ 动态扩展数据
student_attr(id、relation_id、attr_key、attr_value)
relation_id = 横表学生id
只要 relation_id 和主表id一致,这条扩展数据就属于这个学生。
5.3 完整建表示例(可直接执行)
5.3.1 横表:学生主表(固定核心信息)
sql
CREATE TABLE student_main (
id INT PRIMARY KEY AUTO_INCREMENT COMMENT '学生主键ID',
student_name VARCHAR(20) NOT NULL COMMENT '学生姓名',
gender VARCHAR(10) COMMENT '性别',
class_name VARCHAR(20) COMMENT '班级',
create_time DATETIME DEFAULT CURRENT_TIMESTAMP
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='学生主横表';
5.3.2 竖表:学生扩展属性表(动态成绩/动态属性)
sql
CREATE TABLE student_attr (
id INT PRIMARY KEY AUTO_INCREMENT,
relation_id INT NOT NULL COMMENT '关联学生主表ID',
attr_key VARCHAR(50) NOT NULL COMMENT '属性名:语文/数学/爱好/特长',
attr_value VARCHAR(200) COMMENT '属性值',
create_time DATETIME DEFAULT CURRENT_TIMESTAMP
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='学生扩展竖表';
5.4 测试关联数据
横表主数据:
sql
INSERT INTO student_main(student_name,gender,class_name)
VALUES ('小明','男','高一1班');
竖表扩展数据(关联小明 id=1):
sql
INSERT INTO student_attr(relation_id,attr_key,attr_value)
VALUES
(1,'chinese','90'),
(1,'math','85'),
(1,'hobby','打篮球'),
(1,'is_live','是');
此时:横表存固定信息,竖表存无限多动态信息,通过 id 完全绑定。
5.5 横竖表关联查询 SQL(项目最常用)
需求:查询「小明的基础信息 + 所有动态扩展属性」
5.5.1 联表查询(查明细)
sql
SELECT
s.student_name,
s.gender,
s.class_name,
a.attr_key,
a.attr_value
FROM student_main s
LEFT JOIN student_attr a ON s.id = a.relation_id
WHERE s.student_name = '小明';
5.5.2 关联后行转列查询(查完整一条学生数据,前端报表专用)
sql
SELECT
s.student_name,
s.gender,
s.class_name,
MAX(CASE WHEN a.attr_key='chinese' THEN a.attr_value END) AS 语文成绩,
MAX(CASE WHEN a.attr_key='math' THEN a.attr_value END) AS 数学成绩,
MAX(CASE WHEN a.attr_key='hobby' THEN a.attr_value END) AS 特长
FROM student_main s
LEFT JOIN student_attr a ON s.id = a.relation_id
WHERE s.id = 1
GROUP BY s.id,s.student_name,s.gender,s.class_name;
5.6 横竖表关联的核心规则(开发必记)
-
永远横表为主、竖表为从:所有核心业务、主体信息必须在横表
-
关联字段固定:竖表统一使用 relation_id 关联横表主键 id
-
禁止反向关联:绝不拿横表字段去匹配竖表字段
-
一条横表数据,可对应 N 条竖表数据(一对多关系)
5.7 真实业务常见关联场景
-
用户模块:用户主表(横表) + 用户自定义扩展字段(竖表)
-
商品模块:商品主表(横表) + 商品规格属性(竖表)
-
系统配置:网站信息主表(横表) + 动态配置项(竖表)
-
表单问卷:问卷主表(横表) + 用户填写的动态字段数据(竖表)
5.8 为什么要这样关联?(新手终极理解)
如果全部用横表:未知属性太多,频繁加字段、改表结构,极其不规范。
如果全部用竖表:核心数据查询太慢、无法加索引、事务混乱。
最终企业最优解:横表管固定主体,竖表管动态扩展,通过ID一对多关联,兼顾性能 + 灵活性。
5.9 企业核心问题解决:竖表 key 英文存储、前端展示中文(新手最大疑惑)
5.3.1 横表:学生主表(固定核心信息)
sql
CREATE TABLE student_main (
id INT PRIMARY KEY AUTO_INCREMENT COMMENT '学生主键ID',
student_name VARCHAR(20) NOT NULL COMMENT '学生姓名',
gender VARCHAR(10) COMMENT '性别',
class_name VARCHAR(20) COMMENT '班级',
create_time DATETIME DEFAULT CURRENT_TIMESTAMP
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='学生主横表';
5.3.2 竖表:学生扩展属性表(动态成绩/动态属性)
sql
CREATE TABLE student_attr (
id INT PRIMARY KEY AUTO_INCREMENT,
relation_id INT NOT NULL COMMENT '关联学生主表ID',
attr_key VARCHAR(50) NOT NULL COMMENT '属性名:语文/数学/爱好/特长',
attr_value VARCHAR(200) COMMENT '属性值',
create_time DATETIME DEFAULT CURRENT_TIMESTAMP
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='学生扩展竖表';
5.4 测试关联数据
横表主数据:
sql
INSERT INTO student_main(student_name,gender,class_name)
VALUES ('小明','男','高一1班');
竖表扩展数据(关联小明 id=1):
sql
INSERT INTO student_attr(relation_id,attr_key,attr_value)
VALUES
(1,'语文','90'),
(1,'数学','85'),
(1,'特长','打篮球'),
(1,'住校','是');
此时:横表存固定信息,竖表存无限多动态信息,通过 id 完全绑定。
5.5 横竖表关联查询 SQL(项目最常用)
需求:查询「小明的基础信息 + 所有动态扩展属性」
5.5.1 联表查询(查明细)
sql
SELECT
s.student_name,
s.gender,
s.class_name,
a.attr_key,
a.attr_value
FROM student_main s
LEFT JOIN student_attr a ON s.id = a.relation_id
WHERE s.student_name = '小明';
5.5.2 关联后行转列查询(查完整一条学生数据,前端报表专用)
sql
SELECT
s.student_name,
s.gender,
s.class_name,
MAX(CASE WHEN a.attr_key='语文' THEN a.attr_value END) AS 语文成绩,
MAX(CASE WHEN a.attr_key='数学' THEN a.attr_value END) AS 数学成绩,
MAX(CASE WHEN a.attr_key='特长' THEN a.attr_value END) AS 特长
FROM student_main s
LEFT JOIN student_attr a ON s.id = a.relation_id
WHERE s.id = 1
GROUP BY s.id,s.student_name,s.gender,s.class_name;
5.6 横竖表关联的核心规则(开发必记)
-
永远横表为主、竖表为从:所有核心业务、主体信息必须在横表
-
关联字段固定:竖表统一使用 relation_id 关联横表主键 id
-
禁止反向关联:绝不拿横表字段去匹配竖表字段
-
一条横表数据,可对应 N 条竖表数据(一对多关系)
5.7 真实业务常见关联场景
-
用户模块:用户主表(横表) + 用户自定义扩展字段(竖表)
-
商品模块:商品主表(横表) + 商品规格属性(竖表)
-
系统配置:网站信息主表(横表) + 动态配置项(竖表)
-
表单问卷:问卷主表(横表) + 用户填写的动态字段数据(竖表)
5.8 为什么要这样关联?(新手终极理解)
如果全部用横表:未知属性太多,频繁加字段、改表结构,极其不规范。
如果全部用竖表:核心数据查询太慢、无法加索引、事务混乱。
最终企业最优解:横表管固定主体,竖表管动态扩展,通过ID一对多关联,兼顾性能 + 灵活性。
六、表结构设计选型规范(新手开发必守准则)
核心选型口诀:固定字段用横表,动态扩展用竖表;主业务用横表,扩展属性用竖表
4.1 必须使用横表的场景(90%核心业务)
适用标准:业务字段固定、不会频繁新增修改、需要高频查询/关联/统计、作为核心主表
真实业务案例:
-
用户表:id、用户名、手机号、性别、注册时间(字段永久固定)
-
订单表:订单号、用户ID、金额、下单时间、支付状态(核心字段固定)
-
商品主表:商品ID、名称、价格、分类、上架状态(基础属性固定)
-
文章表、日志表、权限表、角色表等基础业务表
4.2 必须使用竖表的场景(动态扩展业务)
适用标准:业务属性不固定、需要随时新增字段、自定义属性、拓展配置类数据
真实业务案例:
-
系统配置表:网站标题、LOGO地址、备案号、功能开关(随时新增配置项)
-
商品规格表:颜色、尺寸、内存、版本、材质(不同商品属性不同)
-
用户拓展属性表:用户自定义标签、个性化资料、额外备注
-
动态表单数据:问卷、报名表单、自定义填报字段
-
多维度统计指标、监控数据、临时业务参数
5.4 企业核心问题解决:竖表 key 英文存储、前端展示中文(新手最大疑惑)
在真实开发中,竖表 attr_key 绝对不会存中文。
行业统一规范:数据库存英文/数字标识(稳定、唯一、无乱码、好判断),页面展示中文名称。
新手最疑惑:英文key存在数据库,前端怎么自动变成中文?要不要多加一列中文字段?
结论先行:不要在竖表里新增中文字段!绝对不规范、冗余极高、后期极难维护。
5.4.1 三种主流解决方案(按企业优先级排序)
方案一:后端代码映射(90%中小项目首选、最简单)
原理:数据库只存标准英文 key,中文名称统一放在后端常量映射表里,查询返回前端时自动替换中文。
数据库存储(标准)
-
chinese → 语文成绩
-
math → 数学成绩
-
english → 英语成绩
-
height → 身高
-
weight → 体重
后端伪代码映射(Java/JS/TS 通用)
javascript
// 全局统一映射字典
const fieldMap = {
chinese: "语文成绩",
math: "数学成绩",
english: "英语成绩",
physics: "物理成绩",
height: "身高",
weight: "体重",
};
// 查询完数据后循环替换中文
resList.forEach((item) => {
item.label = fieldMap[item.attr_key] || item.attr_key;
});
优点:不用改表、无需联表、查询速度最快、统一管理、修改中文只改一处。
缺点:新增字段需要改后端代码。
方案二:单独建「数据字典表」(大型项目/中台/企业级规范)
适用场景:字段超多、经常新增、多模块共用、需要后台配置修改中文名称。
设计思路:
-
竖表只存:attr_key(英文标识)
-
新建一张公共数据字典表,专门存放 key 和中文名称对照
字典表建表语句(通用万能)
sql
CREATE TABLE sys_dict (
id INT PRIMARY KEY AUTO_INCREMENT,
dict_key VARCHAR(50) NOT NULL COMMENT '英文标识key',
dict_label VARCHAR(100) NOT NULL COMMENT '中文展示名称',
sort INT DEFAULT 0 COMMENT '排序',
create_time DATETIME DEFAULT CURRENT_TIMESTAMP
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='通用数据字典表';
存入对照数据
sql
INSERT INTO sys_dict(dict_key,dict_label) VALUES
('chinese','语文成绩'),
('math','数学成绩'),
('english','英语成绩'),
('physics','物理成绩');
联表查询自动带出中文
sql
SELECT
s.relation_id,
s.attr_key,
s.attr_value,
d.dict_label -- 直接查出中文名称
FROM student_attr s
LEFT JOIN sys_dict d ON s.attr_key = d.dict_key
优点:
-
无需改代码,后台直接新增/修改中文名称
-
全项目统一字典,规范度极高
-
支持排序、分类、状态管理
缺点:多一张表、多一次联表查询
方案三:前端本地映射(极简展示类项目)
纯展示型页面、内部后台系统,可直接在前端写映射对象,后端只返回英文key,前端自行翻译中文。
优点:最快、不占用服务端资源
缺点:不通用、后台无法配置、不适合复杂业务
5.4.2 重点解答:能不能竖表加一个「中文名称字段」?
答案:绝对不可以!严禁这样设计!
错误示范:给竖表加 attr_label 字段存储中文
-
严重数据冗余:同一份中文重复存成千上万行
-
修改极其麻烦:想改"语文学分"为"语文成绩",需要批量更新全表数据
-
数据不一致:历史数据、新增数据中文可能不统一
-
完全不符合数据库三大范式
5.4.3 企业最终统一规范(必背)
-
数据库永远存英文key、数字编码(稳定、唯一、可枚举)
-
中文展示名称绝对不存业务竖表
-
小型项目 → 后端代码映射
-
中大型项目/正式后台 → 公共字典表联表查询
-
极简展示页面 → 前端映射
六、表结构设计选型规范(新手开发必守准则)
核心选型口诀:固定字段用横表,动态扩展用竖表;主业务用横表,扩展属性用竖表
6.1 必须使用横表的场景(90%核心业务)
适用标准:业务字段固定、不会频繁新增修改、需要高频查询/关联/统计、作为核心主表
真实业务案例:
-
用户表:id、用户名、手机号、性别、注册时间(字段永久固定)
-
订单表:订单号、用户ID、金额、下单时间、支付状态(核心字段固定)
-
商品主表:商品ID、名称、价格、分类、上架状态(基础属性固定)
-
文章表、日志表、权限表、角色表等基础业务表
6.2 必须使用竖表的场景(动态扩展业务)
适用标准:业务属性不固定、需要随时新增字段、自定义属性、拓展配置类数据
真实业务案例:
-
系统配置表:网站标题、LOGO地址、备案号、功能开关(随时新增配置项)
-
商品规格表:颜色、尺寸、内存、版本、材质(不同商品属性不同)
-
用户拓展属性表:用户自定义标签、个性化资料、额外备注
-
动态表单数据:问卷、报名表单、自定义填报字段
-
多维度统计指标、监控数据、临时业务参数
七、企业级最佳落地实践(避坑指南)
-
主表横表,附表竖表:核心业务主体全部用横表,所有动态拓展属性、配置数据,单独用竖表存储,不污染主表结构
-
存储用竖表,展示用横表:动态属性数据以竖表形式存储节省开发成本,查询报表时通过行转列转为横表展示,兼顾灵活性和展示效果
-
禁止全业务竖表化:核心业务数据严禁用竖表,会导致查询缓慢、事务复杂、索引失效,严重影响系统性能
-
竖表数据规范:所有竖表统一设计关联ID、Key、Value字段,Key值统一命名规范,避免重复、混乱
八、全文终极总结
-
横表(直表):固定结构、查询高效、适合所有核心业务主表,是项目基础表结构
-
竖表(键值表):动态灵活、无需改表,仅用于拓展属性、系统配置、动态表单场景
-
横竖互转核心:竖转行用 CASE 聚合,行转竖用 UNION ALL 拆分,可适配所有同类业务
-
开发核心原则:能⽤横表绝不⽤竖表,竖表只做拓展,不做核心业务存储