MySQL 虚拟列虚拟类型分类

本文介绍了MySQL中VIRTUAL和STORED两种虚拟列的区别:VIRTUAL列动态计算且不占存储,适合计算开销小的情况;STORED列预计算存储,适合频繁查询以提升性能。选择取决于业务需求和性能优化考虑。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

在 MySQL 中,虚拟列有两种类型:VIRTUAL 和 STORED。它们在功能和使用上有一些区别。

1. VIRTUAL 虚拟列:

  • VIRTUAL 虚拟列是通过表达式动态计算得出的值,并不实际存储在磁盘上。
  • 每次查询时,虚拟列的值都会根据定义的表达式进行计算。
  • 虚拟列的值是实时计算的,不占用额外的存储空间。
  • 适用于那些能够通过其他列计算得出的值,而且计算开销较小的情况。

以下是一个示例,说明如何创建和使用 VIRTUAL 虚拟列:

CREATE TABLE products (
  id INT,
  price DECIMAL(10,2),
  discount DECIMAL(3,2),
  discounted_price DECIMAL(10,2) GENERATED ALWAYS AS (price - (price * discount)) VIRTUAL
);

INSERT INTO products (id, price, discount) VALUES (1, 100.00, 0.2);

在上面的示例中,discounted_price 列是一个虚拟列,通过 pricediscount 列的值进行计算得出。每次查询 discounted_price 列时,MySQL 都会实时计算并返回结果。

2. STORED 虚拟列:

  • STORED 虚拟列也是通过表达式计算得出的值,但与 VIRTUAL 不同,STORED 虚拟列的值在插入或更新数据时计算并存储在磁盘上。
  • 存储列的值只有在写入时计算一次,并且在查询时直接读取存储的值,不需要再进行实时计算。
  • 适用于那些频繁被查询而计算开销较高的场景,可以在写入数据时计算一次,然后在查询时直接读取存储的值,提高查询性能。

以下是一个示例,说明如何创建和使用 STORED 虚拟列:

CREATE TABLE sales (
  id INT,
  quantity INT,
  price DECIMAL(10,2),
  total_price DECIMAL(10,2) GENERATED ALWAYS AS (quantity * price) STORED
);

INSERT INTO sales (id, quantity, price) VALUES (1, 10, 5.00);

在上面的示例中,total_price 列是一个存储列,通过 quantityprice 列的值进行计算得出。存储列的值会在插入数据时计算一次,并且存储在磁盘上。每次查询 total_price 列时,MySQL 都会直接读取存储的值,无需进行实时计算。

总结起来,VIRTUAL 虚拟列在每次查询时动态计算值,不占用存储空间,而 STORED 虚拟列在写入数据时计算一次并存储值,适用于频繁查询的场景,可以提高查询性能。选择使用哪种虚拟列类型取决于具体的业务需求和性能优化考虑。

<think>嗯,用户想了解如何在MySQL中添加生成虚拟。首先,我需要回忆一下MySQL的相关文档,尤其是关于Generated Column的部分。记得MySQL从5.7版本开始引入了这个功能,对吗?生成有两种类型虚拟生成和存储生成虚拟的值在查询时实时计算,而存储则在插入或更新时计算并存储。 接下来,用户需要具体的语法和示例。语法结构应该是这样的:在创建表的时候使用GENERATED ALWAYS AS关键字,后面跟上表达式,然后指定VIRTUAL或STORED。例如,在CREATE TABLE语句中添加定义。或者使用ALTER TABLE来添加生成到已存在的表中。 然后,考虑到用户可能的应用场景,比如自动计算年龄或者根据其他字段生成值。比如,用户提到的根据生日计算年龄,这里可能需要用到TIMESTAMPDIFF函数。不过需要注意的是,虚拟不能直接引用动态函数如NOW(),因为每次查询的结果可能不同,这会导致生成的值不稳定。但如果是存储生成,可能会在插入或更新时计算,但动态函数可能还是有问题,需要验证。 然后,想到用户提供的引用内容,其中引用[2]提到使用事件调度器定期更新年龄字段。但如果是生成的话,可能不需要这样,因为生成的值是自动计算的。不过这里可能存在误解,因为生成不能使用动态函数,所以可能需要用存储过程或者事件来更新普通,而不是生成。需要区分清楚。 另外,用户可能遇到的问题包括生成的表达式限制,比如不允许子查询或某些函数。需要提醒用户注意这些限制,并提供正确的表达式示例。 最后,可能需要给出具体的示例,比如在创建表时定义生成,或者修改现有表添加生成。同时,说明两种生成的区别,帮助用户根据需求选择合适的方式。 总结步骤应该是:先介绍生成的概念和类型,然后给出创建和修改表的语法,接着提供示例,如计算全名或年龄,最后注意事项和常见问题解答。</think>### MySQL生成(GENERATED COLUMN)添加方法及示例 MySQL 5.7及以上版本支持两种生成类型: 1. **虚拟生成**(VIRTUAL):实时计算,不占用存储空间 2. **存储生成**(STORED):写入时计算并存储结果 #### 一、基础语法 ```sql -- 创建表时定义 CREATE TABLE 表名 ( 名 数据类型 GENERATED ALWAYS AS (表达式) [VIRTUAL|STORED] ); -- 修改已有表 ALTER TABLE 表名 ADD COLUMN 名 数据类型 GENERATED ALWAYS AS (表达式) [VIRTUAL|STORED]; ``` #### 二、实际应用示例 **场景:自动计算用户年龄** ```sql CREATE TABLE users ( id INT PRIMARY KEY, name VARCHAR(50), birthday DATE, age INT GENERATED ALWAYS AS ( TIMESTAMPDIFF(YEAR, birthday, CURDATE()) ) VIRTUAL ); ``` 此时查询`SELECT * FROM users`会自动显示年龄,但需要注意: - 该表达式使用`CURDATE()`函数,会导致虚拟无法建立索引 - 存储生成需使用固定值表达式[^1] **场景:计算订单总价** ```sql ALTER TABLE orders ADD COLUMN total_price DECIMAL(10,2) GENERATED ALWAYS AS ( quantity * unit_price * (1 - discount) ) STORED; ``` 此存储生成会自动计算结果并保存,支持索引[^1] #### 三、核心注意事项 1. **表达式限制**: - 不能包含子查询 - 不能使用存储函数/用户变量 - 不能引用其他生成MySQL 8.0解除部分限制) 2. **性能影响**: - 虚拟适合高频更新场景 - 存储适合高频读取场景 3. **索引支持**: - 存储生成可创建索引 - 虚拟生成MySQL 5.7.8开始支持索引 #### 四、进阶用法示例 **JSON数据解析(MySQL 8.0+)** ```sql CREATE TABLE product ( id INT PRIMARY KEY, spec JSON, weight DOUBLE GENERATED ALWAYS AS (spec->>"$.weight") VIRTUAL ); ``` **日期格式化** ```sql ALTER TABLE log ADD COLUMN log_date DATE GENERATED ALWAYS AS (DATE(create_time)) VIRTUAL; ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值