原创作者:杨涛涛

函数索引顾名思义就是加给字段加了函数的索引,这里的函数也可以是表达式。所以也叫表达式索引。

MySQL 5.7 推出了虚拟列的功能,MySQL8.0的函数索引内部其实也是依据虚拟列来实现的。

我们考虑以下几种场景:

1.对比日期部分的过滤条件。

SELECT ...

FROM tb1

WHERE date(time_field1) = current_date;

2.两字段做计算。

SELECT ...

FROM tb1

WHERE field2 + field3 = 5;

3.求某个字段中间某子串。

SELECT ...

FROM tb1

WHERE substr(field4, 5, 9) = 'actionsky';

4.求某个字段末尾某子串。

SELECT ...

FROM tb1

WHERE RIGHT(field4, 9) = 'actionsky';

5.求JSON格式的VALUE。

SELECT ...

FROM tb1

WHERE CAST(field4 ->> '$.name' AS CHAR(30)) = 'actionsky';

以上五个场景如果不用函数索引,改写起来难易不同。不过都要做相关修改,不是过滤条件修正就是表结构变更添加冗余字段加额外索引。

比如第1个场景改写为,

SELECT ...

FROM tb1

WHERE time_field1 >= concat(current_date, ' 00:00:00')

AND time_field1 <= concat(current_date, '23:59:59');

再比如第4个场景的改写,

由于是求最末尾的子串,只能添加一个新的冗余字段,并且做相关的计划任务来一定频率的异步更新或者添加触发器来实时更新此字段值。

SELECT ...

FROM tb1

WHERE field4_suffix = 'actionsky';

那我们看到,改写也可以实现,不过这样的SQL就没有标准化而言,后期不能平滑的迁移了。

MySQL 8.0 推出来了函数索引让这些变得相对容易许多。

不过函数索引也有自己的缺陷,就是写法很固定,必须要严格按照定义的函数来写,不然优化器不知所措。

我们来把上面那些场景实例化。

示例表结构,

总记录数

mysql> SELECT COUNT(*)

FROM t_func;

+----------+

| count(*) |

+----------+

| 16384 |

+----------+

1 row in set (0.01 sec)

我们把上面几个场景的索引全加上。

mysql > ALTER TABLE t_func ADD INDEX idx_log_time ( ( date( log_time ) ) ),

ADD INDEX idx_u1 ( ( rank1 + rank2 ) ),

ADD INDEX idx_suffix_str3 ( ( RIGHT ( str3, 9 ) ) ),

ADD INDEX idx_substr_str1 ( ( substr( str1, 5, 9 ) ) ),

ADD INDEX idx_str2 ( ( CAST( str2 ->> '$.name' AS CHAR ( 9 ) ) ) );

QUERY OK,

0 rows affected ( 1.13 sec ) Records : 0 Duplicates : 0 WARNINGS : 0

我们再看下表结构, 发现好几个已经被转换为系统自己的写法了。

MySQL 8.0 还有一个特性,就是可以把系统隐藏的列显示出来。

我们用show extened 列出函数索引创建的虚拟列,

上面5个随机字符串列名为函数索引隐式创建的虚拟COLUMNS。

我们先来看看场景2,两个整形字段的相加,

mysql> SELECT COUNT(*)

FROM t_func

WHERE rank1 + rank2 = 121;

+----------+

| count(*) |

+----------+

| 878 |

+----------+

1 row in set (0.00 sec)

看下执行计划,用到了idx_u1函数索引,

mysql> explain SELECT COUNT(*)

FROM t_func

WHERE rank1 + rank2 = 121\G

*************************** 1. row ***************************

id: 1

select_type: SIMPLE

table: t_func

partitions: NULL

type: ref

possible_keys: idx_u1

key: idx_u1

key_len: 9

ref: const

rows: 878

filtered: 100.00

Extra: NULL

1 row in set, 1 warning (0.00 sec)

那如果我们稍微改下这个SQL的执行计划,发现此时不能用到函数索引,变为全表扫描了,所以要严格按照函数索引的定义来写SQL。

mysql> explain SELECT COUNT(*)

FROM t_func

WHERE rank1 = 121 - rank2\G

*************************** 1. row ***************************

id: 1

select_type: SIMPLE

table: t_func

partitions: NULL

type: ALL

possible_keys: NULL

key: NULL

key_len: NULL

ref: NULL

rows: 16089

filtered: 10.00

Extra: Using where

1 row in set, 1 warning (0.00 sec)

再来看看场景1的的改写和不改写的性能简单对比,

mysql> SELECT *

FROM t_func

WHERE date(log_time) = '2019-04-18'

LIMIT 1\G

*************************** 1. row ***************************

id: 2

rank1: 1

str1: test-actionsky-test

str2: {"age": 30, "name": "dell"}

rank2: 120

str3: test-actionsky

log_time: 2019-04-18 10:04:53

1 row in set (0.01 sec)

我们把普通的索引加上。

mysql > ALTER TABLE t_func ADD INDEX idx_log_time_normal ( log_time );

QUERY OK,

0 rows affected ( 0.36 sec ) Records : 0 Duplicates : 0 WARNINGS : 0

然后改写下SQL看下。

mysql> SELECT *

FROM t_func

WHERE date(log_time) >= '2019-04-18 00:00:00'

AND log_time < '2019-04-19 00:00:00'

*************************** 1. row ***************************

id: 2

rank1: 1

str1: test-actionsky-test

str2: {"age": 30, "name": "dell"}

rank2: 120

str3: test-actionsky

log_time: 2019-04-18 10:04:53

1 row in set (0.01 sec)

两个看起来没啥差别,我们仔细看下两个的执行计划:普通索引

mysql> explain format=json SELECT *

FROM t_func

WHERE log_time >= '2019-04-18 00:00:00'

AND log_time < '2019-04-19 00:00:00'

LIMIT 1\G

*************************** 1. row ***************************

EXPLAIN: {

"query_block": {

"select_id": 1,

"cost_info": {

"query_cost": "630.71"

},

"table": {

"table_name": "t_func",

"access_type": "range",

"possible_keys": [

"idx_log_time_normal"

],

"key": "idx_log_time_normal",

"used_key_parts": [

"log_time"

],

"key_length": "6",

"rows_examined_per_scan": 1401,

"rows_produced_per_join": 1401,

"filtered": "100.00",

"index_condition": "((`ytt`.`t_func`.`log_time` >= '2019-04-18 00:00:00') and (`ytt`.`t_func`.`log_time` < '2019-04-19 00:00:00'))",

"cost_info": {

"read_cost": "490.61",

"eval_cost": "140.10",

"prefix_cost": "630.71",

"data_read_per_join": "437K"

},

"used_columns": [

"id",

"rank1",

"str1",

"str2",

"rank2",

"str3",

"log_time",

"cast(`log_time` as date)",

"(`rank1` + `rank2`)",

"right(`str3`,9)",

"substr(`str1`,5,9)",

"cast(json_unquote(json_extract(`str2`,_utf8mb4'$.name')) as char(9) charset utf8mb4)"

]

}

}

}

1 row in set, 1 warning (0.00 sec)函数索引

mysql> explain format=json SELECT COUNT(*)

FROM t_func

WHERE date(log_time) = '2019-04-18'

LIMIT 1\G

*************************** 1. row ***************************

EXPLAIN: {

"query_block": {

"select_id": 1,

"cost_info": {

"query_cost": "308.85"

},

"table": {

"table_name": "t_func",

"access_type": "ref",

"possible_keys": [

"idx_log_time"

],

"key": "idx_log_time",

"used_key_parts": [

"cast(`log_time` as date)"

],

"key_length": "4",

"ref": [

"const"

],

"rows_examined_per_scan": 1401,

"rows_produced_per_join": 1401,

"filtered": "100.00",

"cost_info": {

"read_cost": "168.75",

"eval_cost": "140.10",

"prefix_cost": "308.85",

"data_read_per_join": "437K"

},

"used_columns": [

"log_time",

"cast(`log_time` as date)"

]

}

}

}

1 row in set, 1 warning (0.00 sec)

mysql>

从上面的执行计划看起来区别不是很大, 唯一不同的是,普通索引在CPU的计算上消耗稍微大点,见红色字体。

历期文章回顾

mysql 8函数索引_新特性解读 | MySQL 8.0 索引特性1-函数索引相关推荐

  1. c语言 字符串 正序再倒序_新特性解读 | MySQL 8.0 索引特性3 -倒序索引

    原创作者:杨涛涛 我们今天来介绍下 MySQL 8.0 引入的新特性:倒序索引. MySQL长期以来对索引的建立只允许正向asc存储,就算建立了desc,也是忽略掉. 比如对于以下的查询,无法发挥索引 ...

  2. 中累计直方图_新特性解读 | MySQL 8.0 直方图

    原创作者:杨涛涛 MySQL 8.0 推出了histogram,也叫柱状图或者直方图.先来解释下什么叫直方图. 关于直方图 我们知道,在DB中,优化器负责将SQL转换为很多个不同的执行计划,完了从中选 ...

  3. 新特性解读 | MySQL 8.0 对 limit 的优化

    作者:杨奇龙 网名"北在南方",资深 DBA,主要负责数据库架构设计和运维平台开发工作,擅长数据库性能调优.故障诊断. 本文来源:原创投稿 *爱可生开源社区出品,原创内容未经授权不 ...

  4. C语言: 定义一个函数int isprime(int n),用来判别一个正整数n是否为素数,若为素数函数返回值为1,否则为0。在主函数中输入一个整数x,调用函数isprime(x)来判断这个整数x是

    原题: 定义一个函数int isprime(int n),用来判别一个正整数n是否为素数,若为素数函数返回值为1,否则为0.在主函数中输入一个整数x,调用函数isprime(x)来判断这个整数x是不是 ...

  5. mysql force index报错_新特性解读 | MySQL 8.0 索引特性4-不可见索引

    MySQL 8.0 实现了索引的隐藏属性.当然这个特性很多商业数据库早就有了,比如ORACLE,在11g中就实现了.我来介绍下这个小特性. 介绍 INVISIBLE INDEX,不可见索引或者叫隐藏索 ...

  6. concat 不是可以识别的 内置函数名称。_新特性解读 | MySQL 8.0 窗口函数详解

    背景 一直以来,MySQL 只有针对聚合函数的汇总类功能,比如MAX, AVG 等,没有从 SQL 层针对聚合类每组展开处理的功能.不过 MySQL 开放了 UDF 接口,可以用 C 来自己写UDF, ...

  7. mysql 复制延迟诊断_新特性解读 | MySQL 8 复制延迟观测新方式,更全面更精准

    转载自公众号:玩转MySQL,作者:洪斌 一直以来 MySQL 复制延迟观测是不完善的,既无法观测到真实的主从延迟,也无法支持复杂的复制拓扑环境,常用的 second_behind_master 指标 ...

  8. 新特性解读 | MySQL 8.0 新密码策略(上)

    作者:杨涛涛 资深数据库专家,专研 MySQL 十余年.擅长 MySQL.PostgreSQL.MongoDB 等开源数据库相关的备份恢复.SQL 调优.监控运维.高可用架构设计等.目前任职于爱可生, ...

  9. mysql applier_新特性解读 | MySQL 8.0.18 有权限控制的复制

    背景 MySQL 8.0.18 以前,从服务器都是在不检查权限的情况下执行复制事务的,这样做是为了能够让主服务器获取所有内容.实际上,这意味着从机完全信任主机.但是,可能存在一些设置,其中更改跨越了主 ...

最新文章

  1. 单词转换(map对象)
  2. 个人易遗忘的代码记录
  3. 14、MySQL位运算符
  4. Redux之compose
  5. apache hive 使用概述
  6. WebIDE push files to ABAP repository
  7. 100份Spring面试问答-最终名单(PDF下载)
  8. 如何做一个合格的面试官?
  9. 调试信息清除小工具的编写
  10. JQ实现 todolist案例(记事本)
  11. 基于C#的MongoDB数据库开发应用(2)--MongoDB数据库的C#开发
  12. MT6763,MT6763T(P23),MT6750T,MT6755(P10)参数比较
  13. 12864液晶 介绍
  14. 有没有好的公文写作范文素材,求助各位网友?
  15. 学习python应用,初识python怎样的感受?
  16. atomic 原子操作
  17. html+css实现静态小米商城界面的学习感受与收获
  18. python图像倾斜校正_python 图像倾斜校正
  19. 隐藏Spring Elements
  20. linux系统下怎么安装.deb文件?

热门文章

  1. python编程购物车_python编写购物车新写法
  2. QT综合示例:QT串口通信
  3. OpenCV学习笔记(十二):边缘检测:Canny(),Sobel(),Laplace(),Scharr滤波器
  4. windows 下 Graphviz 安装及入门教程以及 PlantUML
  5. Linux 动态库和静态库
  6. Replace Data Value with Object(以对象取代数据值)
  7. linux 信号发生器,用STM32实现函数信号发生器
  8. 利用OpenCV的Haar特征目标检测方法进行人脸识别的尝试(一)
  9. 阐述html语言的理解,大学语文课后思考题答案
  10. JAVA入门级教学之(简单的程序测试)