Mysql【索引覆盖、索引下推、索引合并、索引跳跃】介绍

        索引覆盖、索引下推、索引合并、索引跳跃都是Mysql对索引的优化手段,它们的思想就是尽量让查询数据走索引,那它们有什么区别呢?

一、首先介绍一下MySQL体系结构

上图来自MySQL官方文档。
通常把MySQL从上至下分为以下几层:

  • MySQL服务层:包括NoSQL和SQL接口、查询解析器、优化器、缓存和Buffer等组件。
  • 存储引擎层:各种插件式的表格存储引擎,实现事务、索引等各种存储引擎相关的特性。
  • 文件系统层: 读写物理文件。

MySQL服务层负责SQL语法解析、触发器、视图、内置函数、binlog、生成执行计划等,并调用存储引擎层去执行数据的存储和检索。我们后续说到的“索引下推”,它的“下”其实就是指将部分上层(服务层)负责的事情,交给了下层(存储引擎)去处理。

二、再介绍一下它们的概念

1、索引覆盖(Index Covering):索引覆盖是指查询的列包含在索引中,而不需要再次访问数据行。换句话说,查询可以直接从索引中获取所需的数据,而不必去查找实际的数据行。这样可以减少I/O操作,提高查询性能。

2、索引下推(Index Pushdown):索引下推是MySQL5.6中的新技术,是一种数据库查询优化技术,它利用了数据库引擎中的索引和过滤条件,将部分过滤工作下推到存储引擎层面进行处理,从而减少不必要的数据读取和传输。

        在传统的查询执行过程中,数据库引擎首先根据索引定位到符合过滤条件的数据行,并将这些数据行读取到内存中,然后再进一步进行过滤操作。而索引下推则再这一步骤中尽可能将过滤操作下推到存储引擎层面,避免将不符合条件的数据行读取到内存中,减少了IO次数。

索引下推(简称ICP)的条件:

  • 只能用于二级索引(secondary index);
  • explain显示的执行计划中type值(join 类型)为 range 、ref 、 eq_ref 或者 ref_or_null ;
  • 并非全部where条件都可以用ICP筛选,如果where条件的字段不在索引列中,还是要读取整表的记录到server端做where过滤;
  • ICP只可以用于MyISAM和InnnoDB存储引擎;

通过一下命令开启/关闭索引下推(mysql 5.6之后默认开启)

set optimizer_switch="index_condition_pushdown=off";

set optimizer_switch="index_condition_pushdown=on";

3、索引合并(Index Merge):索引合并是指数据库系统在执行查询时,利用多个索引来加速查询的过程。它通过同时使用多个索引,并将它们的结果合并,来获取最终的查询结果。索引合并通常在数据库系统无法选择一个最优的单一索引来满足查询需求时使用。

索引合并又包含三个算法,在explain中显示:

using intersect:
index merge intersection access algorithm(索引合并交集访问算法)。
对于每一个使用到的索引进行查询,查询主键值集合,然后进行合并,求交集,也就是AND运算。

using union:
index merge union access algorithm(索引合并并集访问算法)
容易看出,与上述的算法类似,不过是使用了or连接条件,求并集。
执行流程与index merge intersect 类似,依旧是查询了有序的主键集合,然后进行求并集。

using sort_union:
index merge sort sort-union access algorithm (索引合并排序并集访问算法)
根据索引查询得到主键集合,对于每个主键集合进行排序,然后求并集。

4、索引跳跃(Index Skip Scan):索引跳跃是一种优化技术,用于在多列索引中查找数据,即使查询不是以索引的第一列开始。当索引的第一列选择性很差时,索引跳跃可以跳过该列,并在后续列上进行查找。这可以减少所需的索引扫描次数,从而提高查询性能。

我们可以通过SHOW VARIABLES like '%optimizer_switch%'查看它们的开启情况

index_merge=on(是否开启索引合并),

index_merge_union=on(索引合并中的并集操作),

index_merge_sort_union=on(索引合并中的排序并集操作),

index_merge_intersection=on(索引合并中的交集操作),

engine_condition_pushdown=on(是否开启引擎条件下推功能),

index_condition_pushdown=on(索引条件下推),

mrr=on,mrr_cost_based=on,block_nested_loop=on,

batched_key_access=off,materialization=on,

semijoin=on,loosescan=on,firstmatch=on,duplicateweedout=on,

subquery_materialization_cost_based=on,use_index_extensions=on,

condition_fanout_filter=on,derived_merge=on,use_invisible_indexes=off,

skip_scan=on(索引跳跃),

hash_join=on,subquery_to_derived=off,prefer_ordering_index=on,

hypergraph_optimizer=off,derived_condition_pushdown=on

三、接下来创建一张员工表分别模拟一下这四个场景

1、首先我们创建了一个名为 employees 的表并创建相关索引,有 idnameagedepartment 四个字段。

-- 创建员工表
CREATE TABLE employees (
    ID int NOT NULL AUTO_INCREMENT PRIMARY KEY,
    name VARCHAR(50),
    age int,
    department VARCHAR(50)
);

-- 创建name 和 age 列的联合索引
CREATE INDEX idx_name_age ON employees (name, age);

-- 创建部门列的单列索引
CREATE INDEX idx_department ON employees (department);

-- 创建覆盖了 name 和 department 列的联合索引
CREATE INDEX idx_name_department ON employees (name, department);

-- 创建年龄列的单列索引
CREATE INDEX idx_age ON employees (age);

2、加入一些模拟数据,向数据库插入20条数据

INSERT INTO employees (name, age, department) VALUES
('张三', 30, '人力资源部'),
('李四', 25, '市场部'),
('王五', 35, '财务部'),
('赵六', 28, '信息技术部'),
('刘七', 32, '人力资源部'),
('陈八', 27, '市场部'),
('周九', 40, '财务部'),
('吴十', 26, '信息技术部'),
('郑十一', 33, '人力资源部'),
('孙十二', 29, '市场部'),
('朱十三', 38, '财务部'),
('冯十四', 24, '信息技术部'),
('田十五', 31, '人力资源部'),
('马十六', 26, '市场部'),
('韩十七', 37, '财务部'),
('顾十八', 23, '信息技术部'),
('张十九', 29, '人力资源部'),
('李二十', 28, '市场部'),
('王二十一', 39, '财务部'),
('赵二十二', 27, '信息技术部');

1)索引覆盖场景:因为现在我们数据库有 name 和 age  列的联合索引,当我们只查询 name 和 age时,就会走索引覆盖。

-- 查询员工姓名和年龄【索引覆盖】
SELECT name, age FROM employees;

 我们用explain分析一下:

可以看到type显示的是index,表示查询语句在索引字段中遍历,再通过索引指向存储实际数据的地方,而不需要回表去磁盘遍历;

并且Extra字段里面显示Using index,这个就表示使用了索引覆盖;

2)索引下推场景:因为我们建立了(name,age)的联合索引,在一起作为条件过滤时,两个过滤条件都会下推到存储引擎层进行过滤,而无需返回服务层进行where过滤。

-- 查询姓张并且年龄>20的员工信息【索引下推】

SELECT  *  FROM employees WHERE NAME LIKE '张%'  AND age > 20 ;

我们先关闭索引下推,用explain分析一下:

set optimizer_switch="index_condition_pushdown=off";

可以看到使用了联合索引(name,age),Extra是Using where,也就是表示使用了where条件过滤。

过程:先在存储引擎层通过name索引查询以 '张' 开头的id,再回表查询这部分id的数据,再回到MySQL服务层使用where条件过滤age>20。(联合索引只能走name这一部分)

然后我们打开索引下推,再用explain分析一下:

set optimizer_switch="index_condition_pushdown=on";

可以看到使用了联合索引(name,age),并且Extra是Using index condition,也就是使用了索引下推。

过程:先在存储引擎层通过name索引查询以 '张' 开头的id,然后在这一批id中,继续在存储引擎层通过age索引查出年龄大于20的id,回表查询剩余id的数据,然后将符合条件的数据返回到MySQL服务层。(在储存引擎层过滤了name和age)

因为【使用了索引下推,是在符合name条件的id的基础上,再次筛选符合age条件的id】所以它符合条件的id数量一定小于等于【未使用索引下推,筛选出只符合name条件的id数量】,因为它们都要通过id回表,即索引下推最大限度减少了回表的次数。

3)索引合并场景:因为我们的name和department都是单列索引,在一起作为条件过滤时,会将两个结果集合并,得到最终的结果。

-- 查询姓张并且部门为市场部的员工信息【索引合并】

SELECT  * FROM employees WHERE name = '张三'  OR department = '市场部';

我们使用explain分析一下:

可以看到此时type为index_merge,为索引合并;

同时Extra中显示Using sort_union(idx_name_age,idx_department),表示索引合并中的排序并集操作。

它与索引下推的区别是:

        索引下推应用于联合索引,在存储引擎层面一层一层筛选出符合条件的id集合;而索引合并是应用于多个单列索引,并且将每个单列索引得到的id集合取交集,获得最后符合条件的id集合;

4)索引跳跃场景:因为现在我们数据库有 name 和 age  列的联合索引,当我们只查询 age时,它就会跳过name索引,直接走age索引,不必去匹配最左原则。

-- 查询年龄>20的员工信息【索引跳跃】

SELECT * FROM employees FORCE INDEX(idx_name_age) WHERE age > 20;

我们再次用explain分析一下:

发现它的type是ALL,并没有走索引;

这可能是由于数据量太少,执行器在优化阶段直接选择了全表扫描。

如果走了索引跳跃,应该是下图的场景,Extra为Using index for skip scan;

走索引跳跃有三个条件:

  1. Mysql的版本在8.0以上;
  2. 在优化器选项中设置skip_scan = on;
  3. Msql的优化器认为走索引跳跃的成本更低,效率更快。

索引跳跃可以参考:MySQL8.0优化(一)松散索引扫描/索引跳跃扫描ISS - 掘金 (juejin.cn)

ps:以下是我整理的java面试资料,感兴趣的可以看看。最后,创作不易,觉得写得不错的可以点点关注!

链接:https://www.yuque.com/u39298356/uu4hxh?# 《Java知识宝典》 

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

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

相关文章

深入浅出 -- 系统架构之负载均衡Nginx实现高可用

一、Nginx的高可用 线上如果采用单个节点的方式部署Nginx,难免会出现天灾人祸,比如系统异常、程序宕机、服务器断电、机房爆炸、地球毁灭....哈哈哈,夸张了。但实际生产环境中确实存在隐患问题,由于Nginx作为整个系统的网关层接入…

基于巴法云物联网云平台构建可视化控制网页(以控制LED为例)

0 前言 如今大大小小的物联网云平台非常多,但大部分要收取费用,免费的物联网云平台功能则有很多限制使用起来非常不方便。以百度云物联网云平台为例,它的物可视不支持发布主题,等于可视化界面只能作为数据监控而不具备双向通信的…

算法——哈希表

T04BF 👋专栏: 算法|JAVA|MySQL|C语言 🫵 小比特 大梦想 此篇文章与大家分享分治算法关于哈希表相关算法的专题 如果有不足的或者错误的请您指出! 1.哈希表简介 哈希实际上可以简单认为是一个存储数据的容器,用于快速查找某个元素,时间复杂度仅为O(1),怎…

深入浅出 -- 系统架构之分布式集群的分类

一、单点故障问题 集群,相信诸位对这个概念并不陌生,集群已成为现时代中,保证服务高可用不可或缺的一种手段。 回想起初集中式部署的单体应用,因为只有一个节点,因此当该节点出现任意类型的故障(网络、硬件…

YooAssets 使用相关

## 使用 YooAssets 动态加载原生文件时候 > 原生文件:txt;json;等需要直接保存文件内string字符的文件 需要将打包方式设置成为,PackRawFile 并且加载时候使用 API : YooAssets.LoadRawFileSync()YooAssets.LoadRa…

安卓java打包uniapp原生插件 和 uniapp使用安卓android原生插件

1.uniapp dcloud官方文档 简介 | uni小程序SDK 2.前提,需要有经验的安卓java开发人员,并且同时具备uniapp移动端开发经验。说明:android打包的.aar和uniapp需要的.aar是不一样的,uniapp需要的.aar是需要有一些特定配置的&#x…

在Ubuntu上搭建Prometheus + Grafana监控系统

1.Prometheus 部署 从官网下载页面找到最新的二进制文件下载 cd ~ curl -LO https://github.com/prometheus/prometheus/releases/download/v2.51.1/prometheus-2.51.1.linux-amd64.tar.gz将文件解压到指定目录 tar xf prometheus-2.51.1.linux-amd64.tar.gz -C /usr/local为…

解决IDEA 控制台中文乱码

运行某个项目时IntelliJ IDEA 控制台中文乱码,但其他的项目是正常的。接口文档也显示乱码: 一、修改 IntelliJ IDEA 全局编码、项目编码、属性文件编码 上方导航栏“File→Settings…”进入配置页面,在“Editor”中下滑找到“File Encodings…

centos7.2系统部署ZooKeeper集群和Kafka集群(集群应用系统商城前置环境)

本次实验将使用centos7.2系统部署部署ZooKeeper集群因为Kafka依赖于ZooKeeper,所以我们一并进行部署。 实验所示的资源软件已上传至百度网盘,需要自取。 链接:https://pan.baidu.com/s/1a-7_iAIX0DBAMkF9bhiTcA?pwd2333 提取码&#xff1…

基于javassm实现的农产品供销服务系统

开发语言:Java 框架:ssm 技术:JSP JDK版本:JDK1.8 服务器:tomcat7 数据库:mysql 5.7(一定要5.7版本) 数据库工具:Navicat11 开发软件:eclipse/myeclip…

2024/4/2—力扣—不用加号的加法

代码实现: 思路:位运算,利用了异或和与的特性,异或操作与加操作的区别在于异或操作在二进制状态下两个数同1不进位,只是置为0,其他均相同,那么使用与运算计算进位值,补齐异或操作的缺…

深入理解指针2:数组名理解、一维数组传参本质、二级指针、指针数组和数组指针、函数中指针变量

目录 1、数组名理解 2、一维数组传参本质 3、二级指针 4、指针数组和数组指针 5、函数指针变量 1、数组名理解 首先来看一段代码: int main() {int arr[10] { 1,2,3,4,5,6,7,8,9,10 };printf("%d\n", sizeof(arr));return 0; } 输出的结果是&…

jupyter python paramiko 网络系统运维

概述 通过使用jupyter进行网络运维的相关测试 设备为H3C 联通性测试 import paramiko import time import getpass import re import os import datetimeusername "*****" password "*****" ip "10.32.**.**"ssh_client paramiko.SSHCli…

Nginx配置之localhost和反向代理

文章目录 第一步、查看安装位置和配置文件第二步、web服务器设置第三步、localhost 指令第四步、设置反向代理 清明假期,在家练习Nginx配置,在前期【 linux环境下安装配置nginx代理服务器】已经完成nginx环境搭建,本期主要实践web服务器&…

【分治算法】大整数乘法Python实现

文章目录 [toc]问题描述基础算法时间复杂性 优化算法时间复杂性 Python实现 个人主页:丷从心. 系列专栏:Python基础 学习指南:Python学习指南 问题描述 设 X X X和 Y Y Y都是 n n n位二进制整数,计算它们的乘积 X Y XY XY 基础…

libVLC 音频立体声模式切换

在libVLC中,可以使用libvlc_audio_set_channel函数来设置音频的立体声模式。这个函数允许选择不同的音频通道,例如立体声、左声道、右声道、环绕声等。 /*** Set current audio channel.** \param p_mi media player* \param channel the audio channel…

数据挖掘及其近年来研究热点介绍

🎀个人主页: https://zhangxiaoshu.blog.csdn.net 📢欢迎大家:关注🔍点赞👍评论📝收藏⭐️,如有错误敬请指正! 💕未来很长,值得我们全力奔赴更美好的生活&…

基于单片机16路多路抢答器仿真系统设计

**单片机设计介绍,基于单片机16路多路抢答器仿真系统设计 文章目录 一 概要二、功能设计三、 软件设计原理图 五、 程序六、 文章目录 一 概要 基于单片机16路多路抢答器仿真系统的设计概要主要涵盖硬件设计、软件编程以及功能实现等方面。以下是针对该设计的详细概…

SAP HCM PT 2003修改班次,PP61无法自动更新

今天遇到一个问题,2003修改班次以后PP61无法自动更新,开始一直以为是什么配置点漏掉,但是发现开发机没问题,后来发现是用户选保存的时候选中目标计划的完成,这个是保存到实际计划的,数据存储psoll中&#x…

redis的常用基本命令与持久化

文章目录 redis的基本命令1.授权密码2.增加、覆盖、查询、删除、切换库名、移动、清空数据库 Redis持久化RDB模式主动备份自动备份RDB备份过程 AOF备份模式开启AOF备份模式执行流程 总结 redis的基本命令 1.授权密码 config set requirepass 密码设置完密码需要认证密码以后才…