← 返回题目列表

MySQL 生成列是什么?虚拟生成列和存储生成列有什么区别?

中等 第 19 / 28 题 更新于 2026/07/30
MySQL生成列虚拟列索引

简化版

生成列是由表达式计算出来的列,不直接由业务写入。MySQL 中生成列分为虚拟生成列和存储生成列:虚拟列读取时计算,通常不占实际数据存储;存储列写入时计算并保存,占空间但读取更快。生成列常用于 JSON 字段提取、表达式索引、冗余计算字段和兼容复杂查询。

详细版

生成列能把某个表达式变成表中的列。例如从 JSON 字段里提取 user_id,再给这个生成列建索引,就能提升查询效率。它让“表达式计算”和“索引能力”结合起来。

虚拟生成列更省空间,但查询时要计算;存储生成列占空间,但适合读多写少、计算成本较高的场景。实际选择要看读写比例、表达式复杂度、索引需求和数据库版本支持。

面试时要注意:生成列不是随便冗余字段,它的值由数据库表达式维护,业务不能直接写错。

完整版教学

一、生成列的基本概念

生成列也叫 computed column。

它的值来自同一行其他字段的表达式。

数据库负责计算和维护。

业务插入或更新基础字段后,生成列随之变化。

这可以减少应用层冗余计算错误。

二、创建示例

CREATE TABLE events (
  id BIGINT PRIMARY KEY,
  payload JSON NOT NULL,
  user_id BIGINT GENERATED ALWAYS AS (
    JSON_UNQUOTE(JSON_EXTRACT(payload, '$.userId'))
  ) STORED,
  INDEX idx_user_id (user_id)
);

这个例子从 JSON 中提取用户 id。

然后通过生成列建立索引。

三、虚拟列和存储列

类型计算时机存储成本适合场景
VIRTUAL读取时计算通常更省空间表达式简单、读压力不大
STORED写入时计算并保存占用空间读多写少、表达式复杂
普通冗余列应用维护容易不一致需要人工控制更新时
函数索引直接索引表达式版本相关只为查询优化时

四、和普通冗余字段的区别

普通冗余字段由应用写入。

应用漏更新就会产生不一致。

生成列由数据库根据表达式计算。

它更适合确定性规则。

但复杂业务逻辑不适合都塞进生成列表达式。

五、索引价值

很多查询会对字段做函数或表达式。

如果直接在查询里计算,普通索引可能用不上。

生成列可以把表达式结果持久化成可索引列。

这在 JSON 查询、日期截断、大小写归一化等场景很常见。

生成列最大的工程价值,经常不是少写一行代码,而是让表达式查询可以走索引。

六、限制和注意事项

表达式通常要求确定性。

不能随意引用其他表数据。

字段类型要规划清楚。

大表新增存储生成列可能有 DDL 成本。

不同 MySQL 版本对索引和表达式支持也有差异。

七、误区和追问

  • 误区:生成列就是应用层冗余字段。 生成列由数据库表达式维护,一致性更强。
  • 误区:虚拟列一定比存储列好。 虚拟列省空间,但读取时计算可能增加成本。
  • 误区:所有表达式都适合生成列。 复杂、多表、非确定性业务规则不适合。
  • 追问:JSON 字段如何提高查询性能? 可以提取关键路径为生成列并建索引。
  • 追问:生成列能更新吗? 通常不能直接写入,它由表达式自动生成。
  • 追问:大表加生成列要注意什么? 评估 DDL 锁、回填成本、索引构建和回滚方案。

八、面试收束

先定义生成列。

再比较虚拟和存储。

最后结合 JSON 提取建索引说明真实价值。