MySQL横表(直表/宽表)与竖表(键值表)完整实操学习笔记

适用场景: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;
});

优点:不用改表、无需联表、查询速度最快、统一管理、修改中文只改一处。

缺点:新增字段需要改后端代码。

方案二:单独建「数据字典表」(大型项目/中台/企业级规范)

适用场景:字段超多、经常新增、多模块共用、需要后台配置修改中文名称。

设计思路

  1. 竖表只存:attr_key(英文标识)

  2. 新建一张公共数据字典表,专门存放 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地址、备案号、功能开关(随时新增配置项)

  • 商品规格表:颜色、尺寸、内存、版本、材质(不同商品属性不同)

  • 用户拓展属性表:用户自定义标签、个性化资料、额外备注

  • 动态表单数据:问卷、报名表单、自定义填报字段

  • 多维度统计指标、监控数据、临时业务参数

七、企业级最佳落地实践(避坑指南)

  1. 主表横表,附表竖表:核心业务主体全部用横表,所有动态拓展属性、配置数据,单独用竖表存储,不污染主表结构

  2. 存储用竖表,展示用横表:动态属性数据以竖表形式存储节省开发成本,查询报表时通过行转列转为横表展示,兼顾灵活性和展示效果

  3. 禁止全业务竖表化:核心业务数据严禁用竖表,会导致查询缓慢、事务复杂、索引失效,严重影响系统性能

  4. 竖表数据规范:所有竖表统一设计关联ID、Key、Value字段,Key值统一命名规范,避免重复、混乱

八、全文终极总结

  1. 横表(直表):固定结构、查询高效、适合所有核心业务主表,是项目基础表结构

  2. 竖表(键值表):动态灵活、无需改表,仅用于拓展属性、系统配置、动态表单场景

  3. 横竖互转核心:竖转行用 CASE 聚合,行转竖用 UNION ALL 拆分,可适配所有同类业务

  4. 开发核心原则:能⽤横表绝不⽤竖表,竖表只做拓展,不做核心业务存储

相关推荐
北顾笙9805 分钟前
MYSQL-day03
数据库·sql·mysql
ULIi096kr30 分钟前
MySQL大表优化终极方案:单表数据量上限、卡顿解决、分表分库实战教程
数据库·mysql
deviant-ART38 分钟前
MySQL里的三个concat函数
数据库·mysql
H_老邪1 小时前
1044 - Access denied for user ‘root‘@‘%‘ to database ‘nacos‘
数据库·mysql
凭X而动2 小时前
MySQL 5.7.44 部署
数据库·mysql·部署
Adorable老犀牛2 小时前
MySQL Server Exporter:Prometheus 监控 MySQL/MariaDB 指南
mysql·prometheus·mariadb
范什么特西3 小时前
重点:mybatis注意细节
java·mysql·mybatis
swordbob4 小时前
MySQL和Oracle关于读未提交的区别
数据库·mysql·oracle
林九生4 小时前
【实用技巧】MySQL 绿色版一键路径更新脚本详解 —— update_path.bat 深度解析
android·数据库·mysql
野生技术架构师4 小时前
从 B+ 树到应用层分表:MySQL 海量数据架构解析
数据库·mysql·架构