公号:码农充电站pro

主页:https://codeshellme.github.io

这 5 篇文章是我在学习 MySQL 的过程中,总结的笔记:

  • 第一篇 MySQL 学习笔记1-基础篇
    • 1,关于 SQL
    • 2,一条 SQL 的执行步骤
    • 3,MySQL 存储引擎
    • 4,数据库的基本操作
    • 5,关于自增主键
    • 6,SELECT 语句顺序
    • 7,WHERE 子句
    • 8,DISTINCT 去重
    • 9,关于 COUNT(*) 操作
    • 10,MYSQL 函数
    • 11,GROUP BY 数据分组
    • 12,子查询(嵌套查询)
    • 13,JOIN 连接查询
    • 14,VIEW 视图
    • 15,存储过程
    • 16,临时表
    • 17,MySQL 权限管理
    • 18,Python 操作 MySQL 的库
  • 第二篇 MySQL 学习笔记2-进阶篇-上
    • 19,MySQL 的基础架构
    • 20,数据库缓冲池
    • 21,数据库中的存储结构
    • 22,InnoDB 中表数据的存储
  • 第三篇 MySQL 学习笔记3-进阶篇-中
    • 23,事务处理
    • 24,事务的隔离级别
    • 25,MySQL 中的锁
    • 26,MVCC 多版本并发控制
    • 27,MySQL 传输数据的原理
  • 第四篇 MySQL 学习笔记4-进阶篇-下
    • 28,Join 语句的原理
    • 29,MySQL 如何进行排序
    • 30,MySQL 中 kill 命令的原理
    • 31,MySQL 中的 mysqldump 命令
    • 32,MySQL 主从同步
    • 33,MySQL 主备原理
  • 第五篇 MySQL 学习笔记5-调优篇
    • 34,关于 MySQL 索引
    • 35,定位数据库 SQL 性能问题

34,关于 MySQL 索引

索引的本质目的是快速定位想要查找的数据。

34.1,MySQL 索引的种类

MySQL 中的索引分为:

  • 普通索引:没有任何约束,主要用于提高查询效率。
  • 唯一索引:在普通索引的基础上增加了数据唯一性的约束,一张数据表里可以有多个唯一索引。
  • 主键索引:在唯一索引的基础上增加了不为空的约束,也就是 NOT NULL+UNIQUE,一张表里最多只有一个主键索引。
    • 与主键索引相对应的是非主键索引(又叫二级索引),在使用非主键索引查询数据时,会涉及到回表,因此比主键索引略慢。
    • 主键索引又叫聚集索引,非主键索引又叫非聚集索引
      • 聚集索引:叶子节点包含了行中的所有数据。
      • 非聚集索引:叶子节点只包含了行 id,不包含其它数据,只有通过行 id回表才能查到其它数据。
  • 全文索引:使用的不多,MySQL 自带的全文索引只支持英文。
    • 通常可以采用专门的全文搜索引擎,比如 ElasticSearch。

InnoDB 中的数据保存在主键索引上,所以,对于全表扫描(select * from t;),是直接扫描表 t 的主键索引。

34.2,普通索引与唯一索引的选择

这两类索引在查询能力上是没差别的,主要考虑的是对更新性能的影响,建议你尽量选择普通索引,因为普通索引可以利用change buffer,而唯一索引不能(具体见 24.5 节 change buffer)。

一个即有主键索引,又有非主键索引的例子:

create table T(
	id int primary key, 
	k int not null, 
	name varchar(16),
	index (k)
) engine=InnoDB;

# 表中 R1~R5 的 (ID,k) 值分别为 
# (100,1)、(200,2)、(300,3)、(500,5) 和 (600,6)

其索引结构如下:

在这里插入图片描述

由图可知,主键长度越小,普通索引的叶子节点就越小,普通索引占用的空间也就越小。

以下 SQL 分别使用主键索引和非主键索引:

  • select * from T where ID=500 主键索引
  • select * from T where k=5 非主键索引

34.3,单一索引与联合索引

  • 单一索引:索引列为一列;
  • 联合索引:多个列组合在一起创建的索引。
    • 创建联合索引时,需要注意索引的顺序,因为联合索引 (x, y, z)(z, y, x) 在使用的时候效率可能会存在差别。
    • 联合索引存在最左匹配原则,就是当查询条件中有多个列时,必须按照索引的创建顺序,从左到右,并且不能跳过某一列
      • 比如联合索引 (x, y, z),如果查询条件是 WHERE x=1 AND y=2 AND z=3,就可以匹配上联合索引;
        • WHERE x=1WHERE x=1 AND y=2 也可以使用到索引
      • 如果查询条件是 WHERE y=2,就无法匹配上联合索引(因为跳过了 x)。
        • WHERE y=2 AND z=3WHERE z=3 也无法使用索引
      • 使用一部分(非全部)索引的情况 (可观察 explain 结果中的 key_len)
        • WHERE x=1 AND z=3 (因为跳过了 y
        • WHERE x=1 AND y>2 AND z=3(因为 y 的条件是范围,所以此时只会用到索引的 xy,而不会用到 z
      • SQL条件语句中的字段顺序不重要,因为在逻辑查询优化阶段会自动进行查询重写

一份练习题:

在这里插入图片描述

创建联合索引的例子:

CREATE TABLE `tuser` (
  `id` int(11) NOT NULL,
  `id_card` varchar(32) DEFAULT NULL,
  `name` varchar(32) DEFAULT NULL,
  `age` int(11) DEFAULT NULL,
  `ismale` tinyint(1) DEFAULT NULL,
  PRIMARY KEY (`id`),           # 主键索引
  KEY `id_card` (`id_card`),    # 普通索引
  KEY `name_age` (`name`,`age`)	# 联合索引
) ENGINE=InnoDB

联合索引的结构图如下:

在这里插入图片描述

对于 SQL where name like ‘张 %’" 也可以使用到最左前缀原则。

关于联合索引的索引顺序

因为可以支持最左前缀,所以当已经有了 (a,b) 这个联合索引后,一般就不需要单独在 a 上建立索引了。因此,第一原则是,如果通过调整顺序,可以少维护一个索引,那么这个顺序往往就是需要优先考虑采用的

那么,如果既有联合查询,又有基于 a、b 各自的查询呢?查询条件里面只有 b 的语句,是无法使用 (a,b) 这个联合索引的,这时候你不得不维护另外一个索引,也就是说你需要同时维护 (a,b)、(b) 这两个索引

34.4,关于索引下推

索引下推的机制是为了减少回表次数,从而提高查询效率。

对于 SQL 语句:

select * from tuser where name like '张%' and age=10 and ismale=1;

在 MySQL 5.6 之前,只能从 ID3 开始一个个回表。到主键索引上找出数据行,再对比字段值。

下图中,在 (name,age) 索引里面我特意去掉了 age 的值**,这个过程 InnoDB 并不会去看 age 的值**,只是按顺序把“name 第一个字是’张’”的记录一条条取出来回表。因此,需要回表 4 次。 在这里插入图片描述

而 MySQL 5.6 引入的索引下推优化(index condition pushdown), 可以在索引遍历过程中,对索引中包含的字段先做判断,直接过滤掉不满足条件的记录,减少回表次数

在下图中,InnoDB 在 (name,age) 索引内部就判断了 age 是否等于 10,对于不等于 10 的记录,直接判断并跳过。在这个例子中,只需要对 ID4、ID5 这两条记录回表取数据判断,就只需要回表 2 次。 在这里插入图片描述

34.5,关于索引覆盖

索引的实际数据存储在 B+ 树的叶子节点上:

  • 唯一索引的叶子节点存储了行的所有数据,任何时候都不需要回表操作。
  • 普通索引的叶子节点只存储了行 id 和相应的索引列,如果需要别的列数据,则需要回表。

索引覆盖指的是,普通索引的叶子节点存储了我们所需要的所有(列)数据,从而不需要进行回表,加快了查询速度。

如果要想使用到索引覆盖,尽量不要使用 select *,而只 select 索引中的字段。

34.6,什么时候使用索引

不需要创建索引的情况:

  • 表中的数据比较少的情况下,比如不到 1000 行;
  • 表中的数据重复度大,比如高于 10% 的时候。

34.7,如何创建索引

参照这里

MySQL 5.6 版本以后,创建索引都支持 Online DDL

34.8,如何设计索引

  • 首先一张表的索引个数不宜过多,否则一条记录的增加和修改,会因为过多的索引造成额外的负担。
    • 针对这个情况,当你需要新建索引的时候,首先考虑在原有的索引片上增加索引,也就是采用复合索引的方式,而不是新建一个新的索引。
    • 另外,我们可以定期检查索引的使用情况,对于很少使用到的索引可以及时删除,从而减少索引数量。
  • 其次,在索引片中,也需要控制索引列的数量,通常情况下我们将 WHERE 里的条件列添加到索引中,而 SELECT 中的非条件列则不需要添加。除非 SELECT 中的非条件列数少,并且该字段会经常使用到。
  • 另外,单列索引和复合索引的长度也需要控制,在 MySQL InnoDB 中,系统默认单个索引长度最大为 767 bytes,如果单列索引长度超过了这个限制,就会取前缀索引,也就是取前 255 字符。这实际上也是告诉我们,字符列会占用较大的空间,在数据表设计的时候,尽量采用数值类型替代字符类型,尽量避免用字符类型做主键,同时针对字符字段最好只建前缀索引。

34.9,为字符串数据设计索引(前缀索引)

MySQL 支持前缀索引,即你可以定义字符串的一部分作为索引,如果创建索引时不指定前缀长度,那么索引就会包含整个字符串。

例如下面两个 SQL:

# index1 索引中,包含了每个记录的整个字符串
alter table table_name add index index1(email);

# index2 索引中,对于每个记录都是只取前 6 个字节
alter table table_name add index index2(email(6));

index1index2 的结构如下:

在这里插入图片描述

index1index2 的区别:

  • index1:占用空间更大,性能更好
  • index2:占用空间较小,性能较低,性能低的原因是:
    • 每次在索引上定位到数据之后,还需要回表去判断字符串是否相等
    • 前缀索引也无法利用索引覆盖的特性

在使用前缀索引是,要确定适当的长度,才能确保即节省空间,又不至于太多的性能损失。

34.10,索引的底层数据结构

MySQL 的索引存储在磁盘(速度很慢)上,读取索引时与磁盘的交互越少(重点在于将树的高度降低),性能也就越高。

1,关于平衡二叉树

平衡二叉树不适合作为 MySQL 索引,主要是由于树的深度比较深,从而磁盘交互就比较多。常见的平衡二叉树有:

  • 平衡二叉搜索树:查询时间复杂度O(log2n),树的深度为 O(log2n)
  • 红黑树
2,关于 B 树

B 树是平衡的多叉树,它的高度远小于平衡二叉树。B 树的一个节点可以存储 M 个子节点,M 成为 B 树的阶。在文件系统和数据库系统中的索引结构经常采用 B 树来实现。

在这里插入图片描述

3,关于 B+ 树

B+ 树是B 树的改进版,通常用在数据库中,InnoDB 使用的就是 B+ 树。

B+ 树的优点:

  • B+ 树查询效率更稳定。因为 B+ 树每次只有访问到叶子节点才能找到对应的数据,而在 B 树中,非叶子节点也会存储数据,这样就会造成查询效率不稳定的情况,有时候访问到了非叶子节点就可以找到关键字,而有时需要访问到叶子节点才能找到关键字。
  • B+ 树的查询效率更高,这是因为通常 B+ 树比 B 树更矮胖(阶数更大,深度更低),查询所需要的磁盘 I/O 也会更少。同样的磁盘页大小,B+ 树可以存储更多的节点关键字。
  • 在查询范围上,B+ 树的效率也比 B 树高。这是因为所有关键字都出现在 B+ 树的叶子节点中,并通过有序链表进行了链接。而在 B 树中则需要通过中序遍历才能完成查询范围的查找,效率要低很多。

在这里插入图片描述

4,关于 Hash 索引

在这里插入图片描述

Hash 索引与B+ 树的区别:

  • Hash 索引不能进行范围查询,而 B+ 树可以。
    • 因为 Hash 索引指向的数据是无序的,而 B+ 树的叶子节点是个有序的链表。
  • Hash 索引不支持联合索引的最左侧原则(即联合索引的部分索引无法使用),而 B+ 树可以。
    • 对于联合索引来说,Hash 索引在计算 Hash 值的时候是将索引键合并后再一起计算 Hash 值,所以不会针对每个索引单独计算 Hash 值。因此如果用到联合索引的一个或者几个索引时,联合索引无法被利用。
  • Hash 索引不支持 ORDER BY 排序
    • 因为 Hash 索引指向的数据是无序的,因此无法起到排序优化的作用,而 B+ 树索引数据是有序的,可以起到对该字段 ORDER BY 排序优化的作用。
    • 同理,我们也无法用 Hash 索引进行模糊查询,而 B+ 树可以使用 LIKE 进行模糊查询。

34.11,MySQL 如何使用索引查询数据

一般我们在写 SQL 语句的时候,并没有指定使用哪个索引,使用哪个索引是由 MySQL 自身(优化器)来确定的。

不过我们也可以使用 force 关键字来告诉 MySQL 使用我们指定的索引去查询数据:

# 告诉 MySQL 使用索引 a 来查询数据
select * from t force index(a) where a between 10000 and 20000;

优化器如何选择索引

优化器会根据扫描行数,是否使用临时表,是否排序,是否要回表等因素进行综合判断。

优化器在执行 SQL 之前并不能准确的知道扫描行数,而只能根据统计信息来估算记录数。

可以使用 explain 命令查看一个 SQL 的预估扫描行数(其中 rows 预估扫描行数):

在这里插入图片描述

这个统计信息就是索引的“区分度”(一个索引上不同的值越多,这个索引的区分度就越好)。一个索引上不同的值的个数,我们称之为“基数”(cardinality),这个基数越大,索引的区分度越好。

命令 show index from table_name 可以查看一个表的索引基数(但不一定准确):

在这里插入图片描述

MySQL 通过采样统计来的到索引基数。

重建索引信息

MySQL 有时候会判断错误扫描行数,当你认为 MySQL 判断错误时(大多数时候MySQL是不会选择错误的),可以使用 analyze table table_name 命令来修正索引信息:

在这里插入图片描述

34.12,什么是回表

回表是指,InnoDB 在普通索引 a 上查到主键 id 的值后,再根据一个个主键 id 的值到主键索引上去查整行数据的过程

那么,回表过程是一行行的查数据,还是批量的查数据?

以下面语句为例:

# 字段 a 上有索引
select * from t1 where a>=1 and a<=100;

默认的查询过程是这样的:主键索引是一棵 B+ 树,在这棵树上,每次只能根据一个主键 id 查到一行数据。因此,回表是一行行搜索主键索引的

流程图如下:

在这里插入图片描述

随着 a 的值递增顺序查询的话,id 的值就变成随机的,那么就会出现随机访问,性能相对较差。虽然“按行查”这个机制不能改,但是调整查询的顺序,还是能够加速的

因为大多数的数据都是按照主键递增顺序插入得到的,所以,如果按照主键的递增顺序查询的话,对磁盘的读比较接近顺序读,能够提升读性能。这就是 MRR 优化的设计思路,MRR 即 Multi-Range Read,主要目的是尽量使用顺序读盘。

MRR 优化后的执行流程:

  • 根据索引 a,定位到满足条件的记录,将 id 值放入 read_rnd_buffer 中 ;
  • read_rnd_buffer 中的 id 进行递增排序;
  • 排序后的 id 数组,依次到主键 id 索引中查记录,并作为结果返回。

read_rnd_buffer 的大小由 read_rnd_buffer_size 参数控制。如果步骤 1 中,read_rnd_buffer 放满了,就会先执行完步骤 2 和 3,然后清空 read_rnd_buffer。之后继续找索引 a 的下个记录,并继续循环。

注意:如果想要稳定地使用 MRR 算法,需要设置set optimizer_switch="mrr_cost_based=off"。(官方文档的说法是:现在的优化器策略,判断消耗的时候,会更倾向于不使用 MRR,把 mrr_cost_based 设置为 off,就是固定使用 MRR )

使用了 MRR 优化后的执行流程和 explain 结果:

在这里插入图片描述

explain:

在这里插入图片描述

可以看到 Extra 字段多了 Using MRR,表示用上了 MRR 优化。

MRR 能够提升性能的核心在于,这条查询语句在索引 a 上做的是一个范围查询,可以得到足够多的主键 id。这样通过排序以后,再去主键索引查数据,能体现出“顺序性”的优势。

34.13,索引失效的几种情况

以下几种 where 子句会导致索引失效:

  • 在 where 子句中对字段做函数处理数据类型转换表达式计算。比如:
    • select * from table_name where month(time_col) = 3
    • select * from table_name where id + 1 > 10
    • 注意:当主键是整数类型条件是字符串时,会走索引,比如:
    • select * from member WHERE id = 90000
    • select * from member WHERE id = '90000' 是一样的(前提 id 是数字类型)。
  • 在 where 子句中对字段使用<>,!=,或进行 NULL 判断(包括 IS NULL, IS NOT NULL)。
  • 在 where 子句中使用 INNOT IN
  • 在 where 子句中使用 like 语句,且以 % 开头。
  • 在 where 子句中使用到字符串类型字段时,没有加单引号''
    • 这种情况会导致数据类型转换
    • 比如:select * from member WHERE name = 90000name 是字符串类型)
  • 在 where 子句中,如果在 OR 前的条件列进行了索引,而在 OR 后的条件列没有进行索引,那么索引会失效。
    • 只要用到 OR 就会导致索引失效

35,定位数据库 SQL 性能问题

35.1,数据库优化步骤

在这里插入图片描述

35.2,慢查询

查看慢查询是否已经开启:

mysql > show variables like '%slow_query_log';

在这里插入图片描述

打开慢查询:

mysql > set global slow_query_log='ON';

注意:这种设置只对当前数据库生效,数据库重启后则会失效。若想永久生效则需在配置文件中设置。

在配置文件中设置,可永久生效:

在这里插入图片描述

查看慢查询日志是否开启,以及慢查询日志文件的位置:

mysql > show variables like '%slow_query_log%';

在这里插入图片描述

查看慢查询的时间阈值(单位,默认是10):

mysql > show variables like '%long_query_time%';

在这里插入图片描述

注意:判断条件是大于该时间阈值,而不是大于等于

设置慢查询时间阈值:

mysql > set global long_query_time = 3;

在这里插入图片描述

如果在设置值后,查询发现没有改变,可以关闭当前连接,重新建立与 MySQL 的连接,再次查询。 或者使用 show global variables like '%long_query_time%'

如果将 long_query_time 的值设置为 0,那么所有的查询语句都将被记录在慢查询日志中。

一般情况下,生产环境会设置为 1 秒。

以下命令可以查看当前系统中慢SQL的条数:

> show global status like '%slow_queries%'

关于慢查询,还可以参考这里

35.3,分析慢查询日志

使用 MySQL 自带的 mysqldumpslow 工具统计慢查询日志(这个工具是个 Perl 脚本,需要先安装好 Perl)。

mysqldumpslow 命令的具体参数如下:

  • -s:采用 order 排序的方式,排序方式可以有以下几种。分别是:
    • c(访问次数)
    • t(查询时间)
    • l(锁定时间)
    • r(返回记录)
    • ac(平均查询次数)
    • al(平均锁定时间)
    • ar(平均返回记录数)
    • at(平均查询时间),为默认排序方式。
  • -t:返回前 N 条数据 。
  • -g:后面可以是正则表达式,对大小写不敏感。

比如要按照查询时间排序,查看前两条 SQL 语句:

perl mysqldumpslow.pl -s t -t 2 "C:\ProgramData\MySQL\MySQL Server 8.0\Data\DESKTOP-4BK02RP-slow.log"

在这里插入图片描述

35.4,EXPLAIN 命令

关于 Explain 命令的官方地址:https://dev.mysql.com/doc/refman/8.0/en/explain-output.html

当定位到了查询慢的 SQL 之后,就可以使用 EXPLAIN 工具做针对性的分析:

EXPLAIN SELECT comment_id, product_id, comment_text, product_comment.user_id, user_name 
FROM product_comment 
JOIN user on product_comment.user_id = user.user_id 

结果如下: 在这里插入图片描述

每列的含义如下:

  • id:每个select子句的标识id,描述表的加载顺序
    • id 相同时,执行顺序由上到下
    • id 不同时,id 值越大,越先执行
  • select_type:select 语句的类型,常见类型:
    • SIMPLE:简单查询(查询中不包含子查询或UNION)
    • PRIMARY:主查询(最外层查询-最后加载),查询中包含子查询,那么最外层查询被标记为 PRIMARY
    • SUBQUERY:子查询
    • DERIVED:衍生临时表
    • UNIONUNION 之后的 select 被标记为 UNION
    • UNION RESULT:多个 UNION 合并的结果
  • table:当前使用的表名
  • partitions:显示查询将访问的分区,如果你的查询是基于分区表
  • type:当前表的访问方式
  • possible_keys:有可能被使用到的索引(理论上要用到的索引)
  • key:经过优化器评估最终使用的索引(实际上用到的索引,从 possible_keys 中选出)
    • 如果值为 NULL 表示没有使用索引
    • 如果值为 PRIMARY 表示使用了主键索引
  • key_len:使用到的索引长度,值越小,表示性能越好
  • ref:引用到的上一个表的列
  • rows:要扫描的行数
  • filtered:表示存储引擎返回的数据在server层过滤后,剩下多少满足查询的记录数量的比例,注意是百分比,不是具体记录数
  • Extra:额外的信息说明

数据表的访问类型所对应的 type 列是比较关键的信息,type 可能有以下取值:

在这里插入图片描述

在这些情况里:

  • all 是最坏的情况,表示全表扫描。
  • indexall 差不多,只不过 index 对索引表进行全扫描,这样做的好处是不再需要对数据进行排序,但是开销依然很大。
    • 例如:select id from t;
    • 如果我们在 Extral 列中看到 Using index,说明采用了索引覆盖,也就是索引可以覆盖所需的 SELECT 字段,就不需要进行回表,这样就减少了数据查找的开销。
  • range 表示索引范围扫描。
  • index_merge 说明查询同时使用了两个或以上的索引,最后取了交集或者并集。
  • ref 表示非唯一索引,或者是唯一索引的非唯一性前缀。
  • eq_ref 表示使用主键或唯一索引时产生的访问方式,通常使用在多表联查中。
  • const 表示使用了主键或者唯一索引(所有的部分)与常量值进行比较。
    • 例如:select * from t where id = 1;
    • 需要说明的是:const 类型和 eq_ref 都使用了主键或唯一索引,不过这两个类型有所区别,const 是与常量进行比较,查询效率会更快,而 eq_ref 通常用于多表联查中
  • system 一般用于 MyISAM 或 Memory 表,属于 const 类型的特例,当表只有一行时连接类型为 system。

除了 all 类型外,其他类型都可以使用到索引,但不同的连接方式的效率也会有所不同,效率从低到高依次为:

  • all < index < range < index_merge < ref < eq_ref < const/system

我们在查看执行计划的时候,通常希望执行计划至少可以使用到 range 级别以上的连接方式,如果只使用到了 all 或者 index 连接方式,我们可以从 SQL 语句和索引设计的角度上进行改进。

Extra 字段的含义

我们从 Extra 字段中的内容,也可以获取很多有用的信息。

Extra 字段的常用取值及含义:

  • Using where:表示使用了过滤(SQL中有 where 子句)
  • Using filesort:表示使用了文件排序不利于性能
  • Using index:表示使用了索引覆盖(有利于性能
  • Using index condition:表示使用了普通索引(二级索引)过滤
  • Using temporary:表示查询过程中使用到了临时表不利于性能
    • 常见于 order bygroup by
  • Impossible WHERE:表示 where 子句的条件始终为 false
  • Impossible HAVING:表示 having 子句的条件始终为 false

说明: 如果 where 子句中是普通字段(非索引字段)的过滤,这种过滤是在 server 层完成的,也就是 Using where(主键id 有些特殊); 如果 where 子句中是普通索引(二级索引)的过滤,这种过滤是在 engine 层完成的,也就是 Using index condition

35.5,SHOW PROFILE 命令

SHOW PROFILE 相比 EXPLAIN 能看到更进一步的执行解析,包括 SQL 都做了什么、所花费的时间等。

默认情况下,profiling 是关闭的:

mysql > show variables like 'profiling';

在这里插入图片描述

开启命令如下:

mysql > set profiling = 'ON';

查看下当前会话都有哪些 profiles

mysql > show profiles;

在这里插入图片描述

查看上一个查询的开销:

mysql > show profile;

# 也可以查看指定的 Query ID 的开销,比如:
# `show profile for query 2`
# 查询结果是一样的

在这里插入图片描述

命令 > show profile cpu,block io for query Query_ID号 可以查看更详细的信息,下面这些提示都是不利因素:

在这里插入图片描述

注意:SHOW PROFILE 命令将被弃用,我们可以从 information_schema 中的 profiling 数据表进行查看。