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

原创作者:杨涛涛

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

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的计算上消耗稍微大点,见红色字体。

历期文章回顾

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/506179.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

python上下键不能用_python退格、方向键无法正常使用解决方法

标签&#xff1a;CentOS 6.5 自带的Python 2.6.6 箭头以及退格键(Backspace)可正常使用&#xff1a;自定义所安装的Python 2.7.6却发现箭头以及退格键(Backspace)在使用的时候出现异常&#xff1a;这是由于新升级的Python2.7.6缺少readline开发包的原因&#xff1a;后重新编译、…

python周志_Python几周学习内容小结

环境配置学习python首先是要配置环境&#xff0c;我们选择了Anaconda.什么是Anaconda:专注于数据分析的python发行版本。为什么选择Anaconda:省事省心&#xff0c;分析利器至于下载和安装只要百度一下&#xff0c;你就知道。Python基本语法Python标识符在 Python 里&#xff0c…

python文本分词_【Python】使用jieba对文本进行分词

【参考】#-*- coding:utf-8 -*-importjiebaimportsysreload(sys)sys.setdefaultencoding(utf8)char_x2"考勤机分两大类&#xff1a;第一类是简单打印类&#xff0c;打卡时&#xff0c;原始记录数据通过考勤机直接打印在卡片上&#xff0c;卡片上的记录时间即为原始的考勤信…

mysql进阶知识_Mysql面试知识点总结(进阶篇)

上一篇主要介绍一些基础的mysql知识点&#xff0c;这一篇我们介绍一下mysql比较重要但在开发中我们程序员很少知道的几个大点(自以为是的观点)。数据库设计三范式&#xff1a;第一范式&#xff1a;数据库表的每一列都是不可分割的原子数据项&#xff0c;即列不可拆分。第二范式…

python计算样本方差_Python计算库numpy进行方差/标准方差/样本标准方差/协方差的计算...

使用numpy可以做很多事情&#xff0c;在这篇文章中简单介绍一下如何使用numpy进行方差/标准方差/样本标准方差/协方差的计算。variance: 方差方差(Variance)是概率论中最基础的概念之一&#xff0c;它是由统计学天才罗纳德费雪1918年最早所提出。用于衡量数据离散程度&#xff…

java实现报表_修改带 JAVA 自定义类的报表还要重启应用,咋解决?

这是 JAVA 编译型语言特性决定的&#xff0c;修改 JAVA 程序重启应用也正常。只不过改报表就要重启整个应用就有点夸张了&#xff0c;报表变动比较频繁&#xff0c;每次都重启应用会影响业务的。这个问题的根本原因是耦合性问题&#xff0c;报表里一旦涉及到 JAVA 代码就要跟主…

python中newfile是干嘛用的_Python基础介绍 | File I\O 读写文件

如何用Python读写文件呢&#xff1f;我们有许多种办法&#xff0c;包括使用Pandas或者使用os相关的工具&#xff0c;我们来看一下&#xff1a;首先&#xff0c;得明白文件路径的事情&#xff1a;import oscurrent_file os.path.realpath(file_io.ipynb)print(current file: {}…

mysql share mode_mysql锁:mysql lock in share mode 和 select for update

select ... lock in share modeselect ... for update注意点&#xff1a;1.都在事务内起作用;2.所涉及的是行锁(即innodb引擎);3.保证当前session事务所锁定的行不会被其他session所修改(这里的修改指更新或者删除)&#xff1b;4.select ... lock in share mode是共享锁&#x…

python是谁维护的_Python是维护拆分的更可靠的方法

cde直接结果一位十进制类最近遇到了一个魔术问题。\\ gt; \\ gt; \\ gt;圆(0.215.2)0.21&#xff1a;00 u t26 t&#xff1a;我想要的结果是0.22&#xff0c;这应该是双重存储的原因。那么如何避免呢&#xff1f;搜索很长一段时间后&#xff0c;将其张贴在此处进行记录。导入小…

idea 用iterm 终端_iTerm2 都不会用,还敢自称老司机?(上)

对于需要长期与终端打交道的工程师来说&#xff0c;拥有一款称手的终端管理器是很有必要的&#xff0c;对于 Windows 用户来说&#xff0c;最好的选择是 Xshell&#xff0c;这个大家都没有异议。但对于 MacOS 用户来说&#xff0c;仍然毋庸置疑&#xff0c;iTerm2 就是你要的利…

bootstrap 日历中文_bootstrap日期选择器本地化-中文

最近用bootstrap做项目&#xff0c;所以就顺便搜了下用bootstrap写的日期选择器。搜到的第一和第二条结果虽然是官网&#xff0c;但上面挂的还是基于bootstrap2的日期选择器(此时为北京时间2017-12-26 17:18)&#xff0c;不能与bootstrap3兼容使用。所以又去找bootstrap3的日期…

td之间的间距怎么改_论文的一级标题、二级标题格式怎么弄?

其实论文写好了以后&#xff0c;论文格式的调整也是非常重要的&#xff0c;具体的格式一般有以下几点&#xff1a;标题格式&#xff0c;一级标题、二级标题、三级标题页码格式&#xff0c;一般是正文之前为罗马数字&#xff0c;正文以后为阿拉伯数字&#xff0c;一般是页脚中间…

winform教_电脑绝技教你22天学精Csharp之第十五天winform应用程序补充5

{{1}}$using System;using System.Collections.Generic;using System.ComponentModel;using System.Data;using System.Drawing;using System.Linq;using System.Text;using System.Threading.Tasks;using System.Windows.Forms;using System.IO;namespace _10打开对话框{publi…

python鼠标事件 详解_Python selenium键盘鼠标事件实现过程详解

引言----在实际的web测试工作中&#xff0c;需要配合键盘按键来操作&#xff0c;webdriver的 keys()类提供键盘上所有按键的操作&#xff0c;还可以模拟组合键Ctrla&#xff0c;Ctrlv等。举例&#xff1a;#cordinggbkimport osimport timefrom selenium import webdriverfrom s…

python中webdriver_Python自动化学习--Webdriver中的常用方法

from selenium import webdriverdriver webdriver.Chrome()driver.get("https://www.baidu.com/")#WebDriver 中常用的一些方法"""(1) clear() 清楚文本 例&#xff1a;driver.find_element_by_id("kw").send_keys("测试学习")d…

mysql 1556_mysql导入时Error Code: 1556 - You can't use locks with log tables.

前几天数据库迁移&#xff0c;导入数据时发现报错&#xff0c;如下:Query:LOCK TABLES general_log WRITEError occured at:2011-07-08 10:22:12Line no.:10268Error Code: 1556 - You cant use locks with log tables.因为某些原因一直没有去解决这个问题&#xff0c;后来数据…

plupload怎么设置属性_腾达无线路由器怎么设置,这些是你要知道的

腾达无线路由器怎么设置1、联好线路&#xff1a;到你家的外网网线接路由器的WAN口&#xff0c;你的电脑连到路由器的LAN口(有四个&#xff0c;任意一个均可)&#xff0c;给路由器接通电源。设置的时候&#xff0c;给路由器通电&#xff0c;一根网线直接连电脑和路由器的这个口就…

mysql centos 安装目录在哪_centos中如何查看mysql安装目录在哪

centos中查看mysql安装目录的方法&#xff1a;推荐教程&#xff1a;centos使用教程1、使用ps -ef|grep mysql命令查看&#xff1a;结果&#xff1a;root 17659 1 0 2011 ? 00:00:00 /bin/sh /usr/bin/mysqld_safe --datadir/var/lib/mysql --socket/var/lib/mysql/mysql.sock …

mysql group by 规则_mysql 的group by 满足的规则要求:

版权声明&#xff1a;本文为博主原创文章&#xff0c;遵循 CC 4.0 BY-SA 版权协议&#xff0c;转载请附上原文出处链接和本声明。本文链接&#xff1a;https://blog.csdn.net/u011066470/article/details/97291377————————————————GROUP BY满足的规则:所有sele…

定义加密函数程序python_一个python自定义的加密解密函数

下面是编程之家 jb51.cc 通过网络收集整理的代码片段。编程之家小编现在分享给大家&#xff0c;也给大家做个参考。def encrypt(key,s):b bytearray(str(s).encode("gbk"))n len(b) # 求出 b 的字节数c bytearray(n*2)j 0for i in range(0,n):b1 b[i]b2 b1 ^ k…