MySQL索引使用原则,什么是覆盖索引、索引下堆、离散度……这些概念你弄明白了吗

news2025/2/5 12:09:30

文章目录

  • 一、索引失效的场景
  • 二、列的离散度
  • 三、联合索引最左匹配
    • 1、什么时候用联合索引
    • 2、什么是覆盖索引
  • 四、索引条件下推(ICP)

一、索引失效的场景

MySQL索引失效的场景,什么情况下会造成MySQL索引失效

二、列的离散度

什么是列的离散度?我们先看一下列的离散度 公式:count(distinct(column_name)):count(*),列的全部不同值和所有数据行的比例。数据行数相同的情况下,分子越大,列的离散度就越高。

我们看一下下面的数据,CName的离散度更高,还是CCRedits的离散度更高?很显然CName的离散度更高。
在这里插入图片描述
简单来说,如果列的重复值越多,离散度就越低,重复值越少,离散度就越高

不建议在离散度低的字段上建立索引

没有索引的时候查一遍:

select * from course where ccredits=4;

建立索引之后再查一遍:

ALTER TABLE course DROP INDEX idx_course_ccredits;
ALTER TABLE course ADD INDEX idx_course_ccredits(ccredits); -- 耗时比较久
select  * from course where ccredits=4;

我们发现消耗的时间更久了。如果在B+Tree里面的重复值太多,MySQL的优化器发现走索引跟使用全表扫描差不了多少的时候,就算建了索引,也不一定会走索引。

三、联合索引最左匹配

多条件查询的时候,我们通常会建立联合索引。单列索引可以看成是特殊的联合索引。

比如我们在user表上面,给name和phone建立了一个联合索引:

-- name和phone创建联合索引
ALTER TABLE user_innodb DROP INDEX comidx_name_phone;
ALTER TABLE user_innodb add INDEX comidx_name_phone (name,phone);

在这里插入图片描述
联合索引在B+Tree中是复合的数据结构,它是按照从左到右的顺序来建立搜索树的(name在左边,phone在右边)。从上图可以看出来,name是有序的,phone是无序的。当name相等的时候,phone才是有序的

这个时候我们使用where name = ‘Bob’ and phone = '133xx’去查询数据的时候,B+Tree会优先比较name来确定下一步应该搜索的方向,往左还是往右。如果name相同的时候再比较phone。但是如果查询条件没有name,就不知道第一步应该查询哪个节点,因为建立搜索树的时候,name是第一个比较的因子,所以用不到索引。

1、什么时候用联合索引

我们在建立联合索引的时候,一定要把最常用的列放在最左边。

举个例子:

-- (1)使用两个字段,用到联合索引:
EXPLAIN SELECT * FROM user_innodb WHERE name= '青山' AND phone = '13666666666';
-- (2)用最左边的name字段,用到联合索引:
EXPLAIN SELECT * FROM user_innodb WHERE name= '青山';
-- (3)用最右边的phone字段,无法使用索引,走全表扫描:
EXPLAIN SELECT * FROM user_innodb WHERE phone = '13666666666';

2、什么是覆盖索引

非主键索引,我们先通过索引找到主键索引的键值,再通过主键值查出索引里面没有的数据,它比基于主键索引的查询多扫描了一棵索引树,这个过程就叫回表

例如:

select * from user where name = '张三';

在这里插入图片描述
在二级索引里面,不管是单列索引还是联合索引,如果select的数据列只用从索引中就能够取得,不必从数据区中读取,这时候使用的索引就叫做覆盖索引,这样就避免了回表。

我们先建一个联合索引:

-- name和phone创建联合索引
ALTER TABLE user_innodb DROP INDEX comidx_name_phone;
ALTER TABLE user_innodb add INDEX comidx_name_phone (name,phone);

以下三个查询语句属于覆盖索引:

--覆盖索引
EXPLAIN SELECT name,phone FROM user_innodb WHERE name= '青山' AND phone = '13666666666';
EXPLAIN SELECT name FROM user_innodb WHERE name= '青山' AND phone = '13666666666';
EXPLAIN SELECT phone FROM user_innodb WHERE name= '青山' AND phone = '13666666666';

注意:select * 不是覆盖索引。

如果改成只用where phone 查询呢?按照我们之前的分析,它是用不到索引的。实际上可以用到覆盖索引,优化器觉得用索引更快,所以还是用到了索引。

很明显,因为覆盖索引减少了IO次数,减少了数据的访问量,可以大大地提升查询效率。

四、索引条件下推(ICP)

索引条件下推(Index Condition Pushdown),5.6以后完善的功能。只适用于二级索引。ICP的目标是减少访问表的完整行的读数量 从而减少IO操作。

这里说的下推,其实意思是把过滤的动作在存储引擎做完,而不需要到Server层过滤。

举个例子,我们有这样一张表,在last_name 和first_name上面创建联合索引:

-- 索引下推
drop table employees;
CREATE TABLE `employees` (
 `emp_no` int(11) NOT NULL,
 `birth_date` date  NULL,
 `first_name` varchar(14) NOT NULL,
 `last_name` varchar(16) NOT NULL,
 `gender` enum('M','F') NOT NULL,
 `hire_date` date  NULL,
 PRIMARY KEY (`emp_no`)
) ENGINE=InnoDB ;

alter table employees add index idx_lastname_firstname(last_name,first_name);

INSERT INTO `employees` (`emp_no`, `birth_date`, `first_name`, `last_name`, `gender`, `hire_date`) VALUES (1, NULL, '698', 'liu', 'F', NULL);
INSERT INTO `employees` (`emp_no`, `birth_date`, `first_name`, `last_name`, `gender`, `hire_date`) VALUES (2, NULL, 'd99', 'zheng', 'F', NULL);
INSERT INTO `employees` (`emp_no`, `birth_date`, `first_name`, `last_name`, `gender`, `hire_date`) VALUES (3, NULL, 'e08', 'huang', 'F', NULL);
INSERT INTO `employees` (`emp_no`, `birth_date`, `first_name`, `last_name`, `gender`, `hire_date`) VALUES (4, NULL, '59d', 'lu', 'F', NULL);
INSERT INTO `employees` (`emp_no`, `birth_date`, `first_name`, `last_name`, `gender`, `hire_date`) VALUES (5, NULL, '0dc', 'yu', 'F', NULL);
INSERT INTO `employees` (`emp_no`, `birth_date`, `first_name`, `last_name`, `gender`, `hire_date`) VALUES (6, NULL, '989', 'wang', 'F', NULL);
INSERT INTO `employees` (`emp_no`, `birth_date`, `first_name`, `last_name`, `gender`, `hire_date`) VALUES (7, NULL, 'e38', 'wang', 'F', NULL);
INSERT INTO `employees` (`emp_no`, `birth_date`, `first_name`, `last_name`, `gender`, `hire_date`) VALUES (8, NULL, '0zi', 'wang', 'F', NULL);
INSERT INTO `employees` (`emp_no`, `birth_date`, `first_name`, `last_name`, `gender`, `hire_date`) VALUES (9, NULL, 'dc9', 'xie', 'F', NULL);
INSERT INTO `employees` (`emp_no`, `birth_date`, `first_name`, `last_name`, `gender`, `hire_date`) VALUES (10, NULL, '5ba', 'zhou', 'F', NULL);

现在我们要查询所有姓wang,并且名字最后一个字是zi的员工,比如王胖子,王瘦子:

select * from employees where last_name='wang' and first_name LIKE '%zi' ;

正常情况来说,因为字符是从左往右排序的,当你把%加在前面的时候,是不能基于索引去比较的,所以只有lase_name(姓)这个字段能够用于索引比较和过滤。
所以,正常的查询过程是这样的:
(1)根据联合索引查出所有姓wang的二级索引数据(拿到3个主键:6、7、8)。
(2)回表,到主键索引上查询全部符合条件的数据(3条数据)。
(3)把这3条数据返回给Server层,在Server层过滤出名字以zi结尾的员工。

在这里插入图片描述
注意,索引的比较是在存储引擎进行的,数据记录的比较,是在Server层进行的。而当firse_name的条件不能用于索引过滤时,Server层不会把firse_name的条件传递给存储引擎,所以读取了两条没有必要的记录。比如说,如果满足lase_name='wang’的记录有10万条,就会有99999条没有必要读取的记录。

所以,根据firse_name字段过滤的动作,能不能在存储引擎层完成呢?所以,MySQL使用了索引条件下推
(1)根据联合索引查出所有姓wang的二级索引数据(拿到3个主键:6、7、8)。
(2)然后从二级索引中筛选出first_name以zi结尾的索引(1个索引)。
(3)回表,到主键索引上查询全部符合条件的数据(1条数据),返回给Server层。

在这里插入图片描述
很明显,使用索引条件下推的方式到主键索引上查询的数据更少。

ICP是默认开启的,也就是说针对于二级索引,只要能够把条件下推给存储引擎,它就会下推,不需要我们干预:

-- 关闭ICP
set optimizer_switch='index_condition_pushdown=off';
-- 开启ICP
set optimizer_switch='index_condition_pushdown=on';
-- 查看ICP参数
show variables like 'optimizer_switch';

开启后ICP后的执行计划,Uning index condition表示使用了索引下推:
在这里插入图片描述
关闭ICP后的执行计划,Using where表示在Server层过滤了:
在这里插入图片描述

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

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

相关文章

【Nacos】实战之配置中心加载多个配置文件

目录 复习未拆分前的yaml文件拆分配置文件dataSource.yamlmybatis.yamlother.yaml 微服务同时加载多个远程配置文件修改配置文件 复习 导入依赖在子模块里面创建 bootstrap.yaml 文件bootstrap.yaml 文件 添加需要的远程配置信息开始拆分以前的配置信息 未拆分前的yaml文件 拆…

服务器数据库被360后缀勒索病毒攻击怎么解决,勒索病毒解密

随着网络攻击日益猖獗,数据库遭遇勒索病毒的攻击已成为常见现象。而360后缀勒索病毒是一种恶意软件,它将加密数据库中的文件,并要求受害者支付赎金才能获得解密密钥。近日,我们收到很多企业的求助,企业的服务器被360后…

基于STM32CubeMX与keil采用按键外部中断方式控制LED与蜂鸣器

文章目录 前言1. 电路原理图理解1.1 LED与KEY原理图理解1.2 BEEP蜂鸣器 2. 外部中断配置阐述3. STM32CubeMX配置4. 代码编写4.1 代码编写思路4.2 重写回调函数 TIPS总结 前言 这篇文章详细记录外部中断方式控制LED的亮灭以及蜂鸣器的开关;本文从原理图开始到最后实…

工作日记20230714

1、报文id定义对,类库中和tracking中的报文长度定义一致,但是和一级那边的报文长度定义不一致,对方有可能会收到报文,但是发送方在发出数据后程序会自动中止。 2、结构体 如果定义结构体List的话,不用在()加初始值&a…

分享一下使用finalshell连接虚拟机失败的经历

今天在使用finalshell连接安装的Ubuntu的时候遇到了一点问题,通过root用户连接的时候一直连接失败。 然后照着网上的解决方式一个个试 一、安装oppenssh -server sudo apt-get install openssh-server 然后重启ssh sudo service ssh restart 二、设置密码 最后发…

【架构设计】谈谈防腐层的妙用

文章目录 前言一、一个简单的例子二、防腐层介绍总结 前言 最近在学习了解领域驱动模型DDD相关的内容,但是由于没有实际的项目支撑,所以大都是停留在一些理论层面。我发现这里面的一些设计思想还是非常有实用价值的,可以直接应用于你目前的项…

基于ssm+mybatis+mysql+jsp机票预定系统

基于ssmmybatismysqljsp机票预定系统 一、系统介绍二、功能展示1.主页2.个人中心3.用户管理(管理员)4.客机管理(管理员)5.航班管理(管理员)6.机票管理(管理员) 三、其它系统四、获取源码 一、系统介绍 系统…

nacos设置服务权重

nacos设置服务权重

飞行动力学 - 第8节-着陆性能 之 基础点摘要

飞行动力学 - 第8节-着陆性能 之 基础点摘要 1. 着陆性能1.1 空中直线段S11.2 拉平段S21.3 地面滑跑段S3 2. 着陆性能改善方法3. 起飞性能列举4. 参考资料 1. 着陆性能 总体距离S S1 S2 S3,越短性能越佳。 1.1 空中直线段S1 1.2 拉平段S2 1.3 地面滑跑段S3 2. 着…

三分钟了解Redis HyperLogLog 数据结构

文章目录 0. 前言1. 原理1.2 原理解析 2.实战案例3. Redis从入门到精通系列文章4. 常见问题4.1. 什么是Redis HyperLogLog?4.2. HyperLogLog算法的核心思想是什么?4.3. HyperLogLog算法的误差率如何控制?4.4. HyperLogLog算法的存储空间大小与…

超图数据集概念学习1

以前写过一些数据源数据集有关的博文;从头学习一下; 数据集是同种类型数据的集合,比如:点数据集、线数据集。根据数据类型的不同,分为矢量数据集、格网数据集和影像数据集,以及为了处理特定问题而设计的如路…

​CentOS防火墙操作命令 ​

CentOS防火墙操作命令 1、查看防火墙服务状态 systemctl status firewalld.service 或者查看防火墙的状态: 1 firewall-cmd --state 2、开启、重启防火墙 启动firewall: 1 systemctl start firewalld.service 设置开机自启或禁用: …

【Ceph】基于ceph-deploy部署Ceph集群详解

基于ceph-deploy部署Ceph集群详解 1. 存储基础1.1 单机存储设备1.1.1 单机存储的问题1.1.2 商业存储解决方案 1.2 分布式存储(软件定义的存储SDS)1.2.1 分布式存储的类型 2. Ceph简介2.1 Ceph优势2.2 Ceph架构2.2.1 高层应用接口 2.3 Ceph核心组件2.3.1 …

CTFShow-WEB入门篇文件上传详细Wp(151-170)

WEB入门篇--命令执行详细Wp 文件上传:Web151:Web152:Web153:Web154:Web155:Web156:Web157:Web158:Web159:Web160:Web161:Web162&#…

Java:基本数据类型 和 所占大小

目录 java基本程序结构命名注释数据类型 和 大小整数类型浮点char编码boolean 变量常量final 的作用 java基本程序结构 命名 小驼峰:第一个单词小写,后面的单词大写。 大驼峰:每个单词都大写。 变量,方法:小驼峰。 j…

046、TiDB特性_内存悲观锁(了解)

悲观锁 传统悲观锁有两个性能问题: 磁盘io 需要将lock 的信息持久化到 lock CF中,这个时候产生磁盘io网络io 因为每个Region都是多副本,需要将信息通过网络 发送到Follower的lock CF中。 内存悲观锁 为了解决上面两个问题。 就有个内存悲观…

RPC学习笔记

1、Remote Procedure Call RPC的主要目标是让构建分布式更容易,在提供强大的远程调用能力时不损失本地调用的语义简洁性。为实现该目标,RPC框架需要提供一种透明的调用机制,让使用者不必显示的区别本地调用和远程调用。RPC不是一个协议或者方…

CodeArts Check系统规则集还不够?带你体验如何创建、启用自定义规则集

代码检查(CodeArts Check)是基于云端实现的代码检查服务。建立在多年自动化源代码静态检查技术积累与企业级应用经验的沉淀之上,为用户提供代码风格、通用质量与网络安全风险等丰富的检查能力,提供全面质量报告、便捷闭环处理问题…

BTY生态系统DNS关于DeSoc的构想

2022年5月,以太坊创始人Vitalik Buterin与经济学家Glen Weyl和Flashbots研究员Puja Ohlhaver联合发布了《Decentralized Society: Finding Web3’s Soul》。这篇论文的核心是围绕“Web3灵魂”创造出去中心化社会的可能性。 论文中阐述,当下Web3 更多是表…

Java语言基础

目录 一.代码注释 二.变量与常量 1.标识符 2.关键字 3.变量 4.常量 三.基本数据类型 1.整数类型 2.浮点类型 3.字符类型 1.char型 2.转义字符 4.布尔类型 一.代码注释 在代码中添加注释能提高代码的可读性。注释中包含了程序的信息,可以帮助程序员更…