MySQLSTORED生成列(GeneratedColumn)的使用小结

来源:这里教程网 时间:2026-02-12 11:20:07 作者:
一、什么是生成列(Generated Column)二、STORED 与普通字段有什么区别?三、为什么 STORED 列可以让 SQL 飞起来?四、一个医院真实业务案例:统计工作日到访人数五、使用 STORED,企业级写法来了六、为什么企业更喜欢 STORED 而不是 VIRTUAL?七、STORED 生成列 + dim_date = 双剑合璧最强方案八、生产注意事项九、总结:一句话记住 STORED

在 MySQL 8 中,如果你经常写带函数判断的 SQL,例如:

WHERE WEEKDAY(creatime) < 5

你会发现:

索引无法使用执行计划 type = ALL大表查询慢得像蜗牛

常见的数据计算,比如“是否工作日、是否有效”、“金额是否超过阈值”、“是否逾期”等,都容易写成函数形式,导致索引无法命中。

在高并发、大数据量的场景下,这种写法会拖垮整个系统

解决办法是什么?

???? MySQL 生成列(Generated Column)+ STORED(存储列) + 索引

一、什么是生成列(Generated Column)

MySQL 的生成列有两种:

类型特点VIRTUAL 虚拟列不存储,查询时现算STORED 存储列算完真实写入磁盘,可建索引

生成列的语法:

column_name data_type GENERATED ALWAYS AS (表达式) [VIRTUAL | STORED]

例如,根据 creatime 自动计算是否工作日:

is_workday TINYINT GENERATED ALWAYS AS ( CASE WHEN WEEKDAY(creatime) < 5 THEN 1 ELSE 0 END ) STORED

二、STORED 与普通字段有什么区别?

很多人不清楚为什么“用 STORED 很香”,下面用一个表格秒懂????

对比项普通字段STORED 生成列值由谁计算?开发者自己写入MySQL 根据表达式自动算更新时是否要维护?要自己维护creatime 改,自动重算能否防止脏数据?容易写错、漏改保证永远正确能否建索引?可以可以(而且非常常用)查询时需不需要重新计算?不需要不需要写入性能一般插入时计算一次典型场景普通字段业务派生字段(是否周末、是否逾期、金额区间等)

一句话总结:

STORED = 自动计算的普通字段,可建索引,是 SQL 优化神器。

三、为什么 STORED 列可以让 SQL 飞起来?

来看经典错误写法:

WHERE WEEKDAY(creatime) < 5

你对 creatime 做了函数:

creatime 索引用不了强制全表扫大数据量直接炸

而 STORED 生成列写法:

WHERE is_workday = 1

它是普通字段:

可以建索引非常高效查询极快

MySQL 查询优化器最喜欢:

字段 = 常量
字段 BETWEEN 区间
字段 IN (...)

生成列完美契合这一点。

四、一个医院真实业务案例:统计工作日到访人数

医院表 t_visit

CREATE TABLE t_visit ( id BIGINT PRIMARY KEY AUTO_INCREMENT, hospital_id INT, creatime DATETIME, visit_num INT );

需求:

统计各医院在工作日(周一到周五)的就诊人数

错误写法:索引完全失效!

SELECT SUM(visit_num) FROM t_visit WHERE WEEKDAY(creatime) < 5;

解释:

Creatime 上套函数 → 索引失效查询 100W 行 → 全表扫描业务卡死

五、使用 STORED,企业级写法来了

1)添加生成列

ALTER TABLE t_visit ADD COLUMN is_workday TINYINT GENERATED ALWAYS AS ( CASE WHEN WEEKDAY(creatime) < 5 THEN 1 ELSE 0 END ) STORED, ADD INDEX idx_visit_workday (is_workday, creatime);

2)正确查询写法

SELECT hospital_id, SUM(visit_num) FROM t_visit WHERE is_workday = 1 AND creatime BETWEEN '2025-01-01' AND '2025-02-01' GROUP BY hospital_id;

EXPLAIN 显示:

type = rangekey = idx_visit_workday几万行 → 几千行性能提升 5~30 倍

六、为什么企业更喜欢 STORED 而不是 VIRTUAL?

维度VIRTUALSTORED存储方式不落盘落盘查询成本每查都计算不需要计算能否建 index老版本不支持、多版本有限制全版本支持,生产常用性能适合小数据适合大数据、OLTP、高并发

大量业务都在用:

是否工作日是否节假日是否逾期是否有效金额区间分类(如大单、中单、小单)年龄段分类设备状态派生字段

只要是某列可以推导出来的值,且要做过滤、排序、聚合,80% 的情况下会用 STORED。

七、STORED 生成列 + dim_date = 双剑合璧最强方案

在 BI / 数仓中常用维表:

CREATE TABLE dim_date ( date_key DATE PRIMARY KEY, weekday TINYINT, is_workday TINYINT, is_holiday TINYINT, holiday_name VARCHAR(20) );

事实表:

ALTER TABLE t_visit ADD visit_date DATE GENERATED ALWAYS AS (DATE(creatime)) STORED, ADD INDEX (visit_date);

查询:

SELECT v.hospital_id, SUM(v.visit_num) FROM t_visit v JOIN dim_date d ON v.visit_date = d.date_key WHERE d.is_workday = 1 GROUP BY v.hospital_id;

优势:

超高性能法定节假日、调休随便改报表、看板、数据集市都复用 dim_date企业统一口径

八、生产注意事项

    生成列不能手工 INSERT / UPDATE表插入非常频繁时,STORED 会多一次计算成本(但一般可以接受)表过大时,修改表结构添加 STORED 列要注意线上压力建立索引时一定要注意前导列(选择性越高越好)如果你的计算很复杂,可以考虑 STORED + 函数表达式预处理

九、总结:一句话记住 STORED

STORED 生成列,是 MySQL 自动计算、自动维护、可建索引的派生字段。
它让复杂 SQL 拆分成“插入时算一次,查询时用高速索引”,
是 OLTP 性能优化最常用、最实用也最容易被忽略的武器。

到此这篇关于MySQL STORED 生成列(Generated Column) 的使用小结的文章就介绍到这了,

相关推荐

热文推荐