MySQL 5.7 开始支持了一个新特性 虚拟列(Generated columns , 又称生成列 / 计算列) ,该列的值是通过在列定义时包含的一个计算表达式得到的。
作用: 当我们在where语句中对表内列进行计算时,会导致索引失效而降低查询效率,这种情况可以通过创建虚拟列,提前对字段进行计算,在查询时候直接通过虚拟列筛选即可。
使用场景:
需要对json列进行操作:
-- 对JSON列进行操作时,无法走索引,此时可以通过创建虚拟列直接计算结果,提高筛选效率。
select * from table
where
JSON_CONTAINS(t1.server_types,JSON_OBJECT('serverType', 1))
or
JSON_CONTAINS(t1.server_types,JSON_OBJECT('serverType', 2))
排序时通过多个字段计算:
-- 可以建立虚拟列直接存储计算后的结果,然后再建立索引 提高order by效率。
select * from table
order by has_resource desc, (visit_score * 0.5 + follow_score * 0.3 + app_score * 0.2 + add_score) desc
-- GENERATED ALWAYS可以省略
-- VIRTUAL或 STORED表示虚拟列的存储方式。
ALTER TABLE 表名称 add column 虚拟列名称 虚拟列类型 [GENERATED ALWAYS] as (表达式) [VIRTUAL | STORED];
-- 示例:
-- 通过birthday计算年龄
ALTER TABLE test add column age int as (DATE_FORMAT(FROM_DAYS(TO_DAYS(NOW())-TO_DAYS(birthday)), '%Y')+0 STORED);
虚拟列存储方式:
VIRTUAL 和 STORED类型如何选择:
虚拟列允许
虚拟列不允许
create table test(
json_str json
);
-- 假设表内有很多数据
insert into test values
('[{"type":"name","value":"张三"},{"type":"job","value":"JAVA"}]'),
('[{"type":"name","value":"李四"},{"type":"job","value":"GO"}]'),
('[{"type":"name","value":"王五"},{"type":"job","value":"Python"}]'),
('[{"type":"name","value":"老六"},{"type":"job","value":"PHP"}]');
-- 筛选出 job=java的数据,查询速度很慢
select * from test
where
JSON_EXTRACT(json_str, '$[1].value') = 'JAVA';
-- 创建虚拟列,预先存储job值
alter table test add job varchar(20) as (REPLACE(JSON_EXTRACT(json_str, '$[1].value'),'"',''))
-- 直接筛选虚拟列
select * from test where job = 'JAVA'