《MySQL高级篇》八、索引优化与查询优化(四)

本文涉及的产品
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
RDS MySQL Serverless 高可用系列,价值2615元额度,1个月
云数据库 RDS MySQL,高可用系列 2核4GB
简介: 《MySQL高级篇》八、索引优化与查询优化

9.2 前缀索引对覆盖索引的影响


前面我们说了使用前缀索引可能会增加扫描行数,这会影响到性能。其实,前缀索引的影响不止如此,我们再看一下另外一个场景:


如果使用 index1(即 email 整个字符串的索引结构)的话,可以利用覆盖索引,从 index1 查到结果后直接就返回了,不需要回到 ID 索引再去查一次。而如果使用 index2(即 email(6) 索引结构)的话,就不得不回到 ID 索引再去判断 email 字段的值。


即使你将 index2 的定义修改为 email(18) 的前缀索引,这时候虽然 index2 已经包含了所有的信息,但 InnoDB 还是要回到 id 索引再查一下,因为系统并不确定前缀索引的定义是否截断了完整信息。


select id,email from teacher where email='songhongkangexxx.com';

结论:

使用前缀索引就用不上覆盖索引对查询性能的优化了,这也是你在选择是否使用前缀索引时需要考虑的一个因素。

9.3 拓展内容

对于类似于邮箱这样的字段来说,使用前缀索引的效果可能还不错。但是,遇到前缀的区分度不够好的情况时,我们要怎么办呢?


比如,我们国家的身份证号,一共 18 位,其中前 6 位是地址码,所以同一个县的人的身份证号前 6 位一般会是相同的。


假设你维护的数据库是一个市的公民信息系统,这时候如果对身份证号做长度为 6 的前缀索引的话,这个索引的区分度就非常低了。按照我们前面说的方法,可能你需要创建长度为 12 以上的前缀索引,才能够满足区分度要求。


但是,索引选取的越长,占用的磁盘空间就越大,相同的数据页能放下的索引值就越少,搜索的效率也就会越低。

那么,如果我们能够确定业务需求里面只有按照身份证进行等值查询的需求,还有没有别的处理方法呢?这种方法,既可以占用更小的空间,也能达到相同的查询效率。有!


**第一种方式是使用倒序存储。**如果你存储身份证号的时候把它倒过来存,每次查询的时候:

mysql> select field list from teacher where id_card=reverse(input_id_card_string);

由于身份证号的最后 6 位没有地址码这样的重复逻辑,所以最后这 6 位很可能就提供了足够的区分度。当然,实践中你还要使用 count(distinct) 方法去做验证。


**第二种方式是使用 hash 字段。**你可以在表上再创建一个整数字段,来保存身份证的校验码,同时在这个字段上创建索引。

mysql> alter table teacher add id_card_crc int unsignedadd index(id_card_crc);

然后每次插入新记录的时候,都同时用 crc32() 这个函数得到校验码填到这个新字段,由于校验码可能存在冲突,也就是说两个不同的身份证号通过 crc32() 函数得到的结果可能是相同的,所以你的查询语句 where 部分要判断 id_card 的值是否精确相同。

mysql> select field list from twhere id_card_rc=crc32(input_id_card_string) and id_card=input id_card_string

这样,索引的长度变成了4个字节,比原来小了很多。


从查询效率上看,使用 hash 字段方式的查询性能相对更稳定一些,因为 crc32 算出来的值虽然有冲突的概率但是概率非常小,可以认为每次查询的平均扫描行数接近 1。而倒序存储方式毕竟还是用的前缀索引的方式,也就是说还是会增加扫描行数。

10. 索引下推

Index Condition Pushdown(ICP) 是 MySQL 5.6 中新特性,是一种在存储引擎层使用索引过滤数据的一种优化方式。ICP 可以减少存储引擎访问基表的次数以及 MySQL 服务器访问存储引擎的次数

10.1 使用前后对比


在不使用 ICP 索引扫描的过程:


storage 层:只将满足 index key 条件的索引记录对应的整行记录取出,返回给 server 层

server 层:对返回的数据,使用后面的 where 条件过滤,直至返回最后一行。

使用 ICP 扫描的过程:


storage层:首先将 index key 条件满足的索引记录区间确定,然后在索引上使用 index filter 进行过滤。将满足的 index filter 条件的索引记录才去回表取出整行记录返回 server 层。不满足 index filter 条件的索引记录丢弃,不回表、也不会返回 server 层。

server 层:对返回的数据,使用 table filter 条件做最后的过滤。

使用前后的成本差别:


使用前,存储层多返回了需要被 index filter 过滤掉的整行记录

使用 ICP 后,直接就去掉了不满足 index filter 条件的记录,省去了他们回表和传递到 server 层的成本。

ICP 的加速效果取决于在存储引擎内通过 ICP 筛选掉的数据的比例。

索引中包含这个字段,但是没有使用到这个字段的索引(比如‘%a%’),却可以使用这个字段在索引中进行条件过滤,从而减少回表的记录条数,这种情况就叫做索引下推


10.2 ICP 的开启、关闭


默认情况下启用索引条件下推。可以通过设置系统变量 optimizer_switch 控制 indexcondition_pushdown


#关闭索引下推
SET optimizer_switch=index_condition_pushdown=off;
#打开索引下推
SET optimizerswitch=indexcondition_pushdown=on;
  • 当使用索引条件下推时,EXPLAIN语句输出结果中Extra列内容显示为Using index condition

10.3 ICP 使用案例


f9ac7ee89496f32f9b162cb95f2c93be.png

为该表定义联合索引 zip_last_first(zipcode, lastname, firstname) 。如果我们知道了一个人的邮编,但是不确定这个人的姓氏,我们可以进行如下检索:

SELECT * FROM people
WHERE zipcode= '000001'
AND lastname LIKE '%张%'
AND address LIKE '%北京市%';


执行查看SQL的查询计划,Extra 中显示了Using index condition ,这表示使用了索引下推。即:先使用索引的zipcode字段进行匹配,然后 索引下推 使用lastname字段进行过滤,最后再进行回表。


另外,Using where表示条件中包含需要过滤的非索引列的数据,即address LIKE '%北京市%'这个条件并不是索引列,需要在服务端过滤掉。


aa8619993d6bf6e18de04ce46341c857.png


a3c32c6d127812f5764b28aae57c28b6.png


77d3772f97b70c6b1299a8b074134f15.png


11.4 开启和关闭ICP的性能对比


679794525ef0ec6d97361a56392386dd.png

be3a1dc2f69807f5c78f7363cc1d40f8.png


结果如下:


f411523446c4d575f592e4ddfd311dff.png


多次测试效率对比来看,使用ICP优化的查询效率会好一些。这里建议多存储一些数据效果更明显。


10.5 ICP 的使用条件


只能用于二级索引(secondary index)

explain 显示的执行计划中 type 值(join 类型)为 range 、 ref 、 eq_ref 或者 ref_or_null 。

并非全部 where 条件都可以用 ICP 筛选,如果 where 条件的字段不在索引列中,还是要读取整表的记录到 server 端做 where 过滤。

ICP 可以用于 MyISAM 和 InnnoDB 存储引擎

MySQL 5.6 版本的不支持分区表的 ICP 功能,5.7 版本的开始支持。

当 SQL 使用覆盖索引时,不支持 ICP 优化方法。


11. 普通索引 vs 唯一索引


在不同的业务场景下,应该选择普通索引,还是唯一索引?


假设你在维护一个居民系统,每个人都有一个唯一的身份证号,而且业务代码已经保证了不会写入两个重复的身份证号。如果居民系统需要按照身份证号查姓名:

select name from CUser where id_card='xxxxxxxyyyyyyzzzzz';

所以,你一定会考虑在 id_card 字段上建索引。

由于身份证号字段比较大,不建议把身份证号当做主键。现在有两个选择,要么给 id_card 字段创建 唯一素引,要么创建一个普通索引。如果业务代码已经保证了不会写入重复的身份证号,那么这两个选择逻辑上都是正确的。


你知道的,InnoDB 的数据是按数据页为单位来读写的。也就是说,当需要读一条记录的时候,并不是将这个记录本身从磁盘读出来,而是以页为单位,将其整体读入内存。在 InnoDB中,每个数据页的大小默认是16KB


从性能的角度考虑,你选择唯一索引还是普通索引呢?选择的依据是什么呢?


假设,我们有一个主键列为 ID 的表,表中有字段 k,并且在 k 上有索引,假设字段 k 上的值都不重复。 这个表的建表语句是:

mysql> create table test(
    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)。

相关实践学习
每个IT人都想学的“Web应用上云经典架构”实战
本实验从Web应用上云这个最基本的、最普遍的需求出发,帮助IT从业者们通过“阿里云Web应用上云解决方案”,了解一个企业级Web应用上云的常见架构,了解如何构建一个高可用、可扩展的企业级应用架构。
MySQL数据库入门学习
本课程通过最流行的开源数据库MySQL带你了解数据库的世界。   相关的阿里云产品:云数据库RDS MySQL 版 阿里云关系型数据库RDS(Relational Database Service)是一种稳定可靠、可弹性伸缩的在线数据库服务,提供容灾、备份、恢复、迁移等方面的全套解决方案,彻底解决数据库运维的烦恼。 了解产品详情: https://www.aliyun.com/product/rds/mysql 
相关文章
|
5月前
|
存储 SQL 关系型数据库
mysql底层原理:索引、慢查询、 sql优化、事务、隔离级别、MVCC、redolog、undolog(图解+秒懂+史上最全)
mysql底层原理:索引、慢查询、 sql优化、事务、隔离级别、MVCC、redolog、undolog(图解+秒懂+史上最全)
mysql底层原理:索引、慢查询、 sql优化、事务、隔离级别、MVCC、redolog、undolog(图解+秒懂+史上最全)
|
5月前
|
存储 关系型数据库 MySQL
MySQL数据库索引的数据结构?
MySQL中默认使用B+tree索引,它是一种多路平衡搜索树,具有树高较低、检索速度快的特点。所有数据存储在叶子节点,非叶子节点仅作索引,且叶子节点形成双向链表,便于区间查询。
191 4
|
7月前
|
存储 关系型数据库 MySQL
阿里面试:MySQL 一个表最多 加几个索引? 6个?64个?还是多少?
阿里面试:MySQL 一个表最多 加几个索引? 6个?64个?还是多少?
阿里面试:MySQL 一个表最多 加几个索引? 6个?64个?还是多少?
|
6月前
|
SQL 缓存 关系型数据库
MySQL 慢查询是怎样优化的
本文深入解析了MySQL查询速度变慢的原因及优化策略,涵盖查询缓存、执行流程、SQL优化、执行计划分析(如EXPLAIN)、查询状态查看等内容,帮助开发者快速定位并解决慢查询问题。
260 0
|
4月前
|
缓存 关系型数据库 MySQL
降低MySQL高CPU使用率的优化策略。
通过上述方法不断地迭代改进,在实际操作中需要根据具体场景做出相对合理判断。每一步改进都需谨慎评估其变动可能导致其他方面问题,在做任何变动前建议先在测试环境验证其效果后再部署到生产环境中去。
216 6
|
5月前
|
存储 SQL 关系型数据库
MySQL 核心知识与索引优化全解析
本文系统梳理了 MySQL 的核心知识与索引优化策略。在基础概念部分,阐述了 char 与 varchar 在存储方式和性能上的差异,以及事务的 ACID 特性、并发事务问题及对应的隔离级别(MySQL 默认 REPEATABLE READ)。 索引基础部分,详解了 InnoDB 默认的 B+tree 索引结构(多路平衡树、叶子节点存数据、双向链表支持区间查询),区分了聚簇索引(数据与索引共存,唯一)和二级索引(数据与索引分离,多个),解释了回表查询的概念及优化方法,并分析了 B+tree 作为索引结构的优势(树高低、效率稳、支持区间查询)。 索引优化部分,列出了索引创建的六大原则
140 2
|
6月前
|
存储 关系型数据库 MySQL
MySQL覆盖索引解释
总之,覆盖索引就像是图书馆中那些使得搜索变得极为迅速和简单的工具,一旦正确使用,就会让你的数据库查询飞快而轻便。让数据检索就像是读者在图书目录中以最快速度找到所需信息一样简便。这样的效率和速度,让覆盖索引成为数据库优化师傅们手中的尚方宝剑,既能够提升性能,又能够保持系统的整洁高效。
170 9
|
5月前
|
存储 SQL 关系型数据库
MySQL 动态分区管理:自动化与优化实践
本文介绍了如何利用 MySQL 的存储过程与事件调度器实现动态分区管理,自动化应对数据增长,提升查询性能与数据管理效率,并详细解析了分区创建、冲突避免及实际应用中的关键注意事项。
211 0
|
7月前
|
机器学习/深度学习 关系型数据库 MySQL
对比MySQL全文索引与常规索引的互异性
现在,你或许明白了这两种索引的差异,但任何技术决策都不应仅仅基于理论之上。你可以创建你的数据库实验环境,尝试不同类型的索引,看看它们如何影响性能,感受它们真实的力量。只有这样,你才能熟悉它们,掌握什么时候使用全文索引,什么时候使用常规索引,以适应复杂多变的业务需求。
192 12
|
3月前
|
缓存 关系型数据库 BI
使用MYSQL Report分析数据库性能(下)
使用MYSQL Report分析数据库性能
153 3

推荐镜像

更多