当前位置: 代码网 > it编程>数据库>Mysql > MySQL STORED 生成列(Generated Column) 的使用小结

MySQL STORED 生成列(Generated Column) 的使用小结

2026年02月11日 Mysql 我要评论
在 mysql 8 中,如果你经常写带函数判断的 sql,例如:where weekday(creatime) < 5你会发现:索引无法使用执行计划 type = all大表查询慢得像蜗牛常见的

在 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 = range
  • key = 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
  • 企业统一口径

八、生产注意事项

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

九、总结:一句话记住 stored

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

到此这篇关于mysql stored 生成列(generated column) 的使用小结的文章就介绍到这了,更多相关mysql stored 生成列内容请搜索代码网以前的文章或继续浏览下面的相关文章希望大家以后多多支持代码网!

(0)

相关文章:

版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。

发表评论

验证码:
Copyright © 2017-2026  代码网 保留所有权利. 粤ICP备2024248653号
站长QQ:2386932994 | 联系邮箱:2386932994@qq.com