作者:杨涛涛
函数索引顾名思义就是加给字段加了函数的索引,这里的函数也可以是表达式。所以也叫表达式索引。
MySQL 5.7 推出了虚拟列的功能,MySQL8.0的函数索引内部其实也是依据虚拟列来实现的。
我们考虑以下几种场景:
1. 对比日期部分的过滤条件。
2. 两字段做计算。
3. 求某个字段中间某子串。
4. 求某个字段末尾某子串。
5. 求JSON格式的VALUE。
以上五个场景如果不用函数索引,改写起来难易不同。不过都要做相关修改,不是过滤条件修正就是表结构变更添加冗余字段加额外索引。
比如第1个场景改写为,
再比如第4个场景的改写,
由于是求最末尾的子串,只能添加一个新的冗余字段,并且做相关的计划任务来一定频率的异步更新或者添加触发器来实时更新此字段值。
那我们看到,改写也可以实现,不过这样的SQL就没有标准化而言,后期不能平滑的迁移了。
MySQL 8.0 推出来了函数索引让这些变得相对容易许多。
不过函数索引也有自己的缺陷,就是写法很固定,必须要严格按照定义的函数来写,不然优化器不知所措。
我们来把上面那些场景实例化。
示例表结构,
总记录数
我们把上面几个场景的索引全加上。
我们再看下表结构, 发现好几个已经被转换为系统自己的写法了。
MySQL 8.0 还有一个特性,就是可以把系统隐藏的列显示出来。
我们用show extened 列出函数索引创建的虚拟列,
看下执行计划,用到了idx_u1函数索引,
那如果我们稍微改下这个SQL的执行计划,发现此时不能用到函数索引,变为全表扫描了,所以要严格按照函数索引的定义来写SQL。
再来看看场景1的的改写和不改写的性能简单对比,
我们把普通的索引加上。
然后改写下SQL看下。
两个看起来没啥差别,我们仔细看下两个的执行计划:
- 普通索引
- 函数索引
从上面的执行计划看起来区别不是很大, 唯一不同的是,普通索引在CPU的计算上消耗稍微大点,见红色字体。
当然,有兴趣的可以大并发的测试下,我这仅仅作为功能性进行一番演示。