MySQL中的回表查询、索引覆盖、索引下推

news2024/9/20 15:29:40

本文重点介绍索引中的常见概念:回表查询、索引覆盖、索引下推

image-20240822210201904

一、回表查询

我们首先理解:在InnoDB存储引擎中,根据索引的存储形式,又可以分为以下两种:

分类含义特点
聚集索引 (Clustered Index)将数据存储与索引放到了一块,索引结构的叶子节点保存了行数据必须有,而且只有一个
二级索引 (Secondary Index)将数据与索引分开存储,索引结构的叶子节点关联的是对应的主键可以存在多个

聚集索引选取规则

  • 如果存在主键,主键索引就是聚集索引。
  • 如果不存在主键,将使用第一个唯一(UNIQUE)索引作为聚集索引。
  • 如果表没有主键,或没有合适的唯一索引,则InnoDB会自动生成一个rowid作为隐藏的聚集索引

聚集索引和二级索引的具体结构如下:

image-20240822194408392

  • 聚集索引的叶子节点下挂的是这一行的数据 。
  • 二级索引的叶子节点下挂的是该字段值对应的主键值

接下来,我们来分析一下,当我们执行如下的SQL语句时,具体的查找过程是什么样子的。

image-20240822194540592

具体过程如下:

  • ①. 由于是根据name字段进行查询,所以先根据name='Arm’到name字段的二级索引中进行匹配查找。但是在二级索引中只能查找到 Arm 对应的主键值 10。
  • ②. 由于查询返回的数据是*,所以此时,还需要根据主键值10,到聚集索引中查找10对应的记录,最终找到10对应的行row。
  • ③. 最终拿到这一行的数据,直接返回即可。

得到回表查询的概念:

回表查询: 这种先到二级索引中查找数据,找到主键值,然后再到聚集索引中根据主键值,获取数据的方式,就称之为回表查询。

以下两条SQL语句,那个执行效率高? 为什么?

-- A语句
-- 备注: id为主键,name字段创建的有索引;
select * from user where id = 10 ;
-- B语句
select * from user where name = 'Arm' ;

A 语句的执行性能要高于B 语句。

因为A语句直接走聚集索引,直接返回数据。 而B语句需要先查询name字段的二级索引,然后再查询聚集索引,也就是需要进行回表查询。

二、索引覆盖

索引覆盖(Index Covering)是指通过在索引中包含所有查询语句中所需的列,可以避免对表中的数据进行额外的访问,从而提高查询效率。(避免了回表操作)

例如,对于一个查询语句:

SELECT col1, col2, col3 FROM table WHERE col1 = x AND col2 = y

如果在table表中建立了一个索引,包含col1、col2和col3三列,那么MySQL可以通过索引定位到符合条件的数据,并在索引中提取col1、col2和col3列的值,无需对表中的数据进行额外的访问。这种方式就叫做索引覆盖。

索引覆盖能够显著提高查询效率,因此在建立索引时应尽量考虑包含查询语句中所需的所有列。

我们实际性进行测试:

-- 创建数据库
CREATE DATABASE IndexCoveringDemo;
USE IndexCoveringDemo;

-- 创建表
CREATE TABLE employees (
    id INT PRIMARY KEY AUTO_INCREMENT,
    first_name VARCHAR(50),
    last_name VARCHAR(50),
    department VARCHAR(50),
    salary DECIMAL(10, 2),
    INDEX idx_name_department_salary (first_name, department, salary)
);
-- 插入随机数据
INSERT INTO employees (first_name, last_name, department, salary)
VALUES
('John', 'Doe', 'Engineering', 75000.00),
('Jane', 'Smith', 'Marketing', 55000.00),
('Alice', 'Johnson', 'Sales', 60000.00),
('Bob', 'Brown', 'Engineering', 80000.00),
('Charlie', 'Davis', 'HR', 50000.00),
('Emily', 'Wilson', 'Sales', 65000.00),
('David', 'Clark', 'Engineering', 70000.00),
('Frank', 'Moore', 'Marketing', 52000.00),
('Grace', 'Taylor', 'HR', 48000.00),
('Henry', 'Miller', 'Sales', 72000.00);

假设我们要查询Engineering部门中first_namesalary,我们可以利用之前创建的复合索引来进行索引覆盖查询。

EXPLAIN SELECT first_name, salary FROM employees WHERE department = 'Engineering';

image-20240822210807896

在这个查询中,first_namesalary两个字段都包含在索引idx_name_department_salary中,department字段是索引的一部分。这个查询将可以通过索引直接返回数据,而不需要访问实际的表数据。

如果我们查询的字段不完全包含在索引中,则MySQL将无法进行索引覆盖,需要访问表数据。

EXPLAIN SELECT first_name, last_name FROM employees  WHERE department = 'Engineering';

image-20240822210942194

在这个查询中,last_name字段不在索引idx_name_department_salary中,因此MySQL不能使用索引覆盖查询。

索引覆盖能够显著提升查询性能,尤其是在涉及大量数据时。通过合理设计复合索引,可以使查询仅通过索引就能返回所有所需的数据,从而减少磁盘I/O并加快查询速度。在设计索引时,需要权衡字段选择,确保常用查询尽可能通过索引覆盖来优化。

三、索引下推

索引下推(INDEX CONDITION PUSHDOWN,简称 ICP)是在 MySQL 5.6 针对扫描二级索引的一项优化改进。总的来说是通过把索引过滤条件下推到存储引擎,来减少 MySQL 存储引擎访问基表的次数以及 MySQL 服务层访问存储引擎的次数。ICP 适用于 MYISAM 和 INNODB,本篇的内容只基于 INNODB。

image_aYUPBYmp7a

  • MySQL 服务层:也就是 SERVER 层,用来解析 SQL 的语法、语义、生成查询计划、接管从 MySQL 存储引擎层上推的数据进行二次过滤等等。
  • MySQL 存储引擎层:按照 MySQL 服务层下发的请求,通过索引或者全表扫描等方式把数据上传到 MySQL 服务层。
  • MySQL 索引扫描:根据指定索引过滤条件,遍历索引找到索引键对应的主键值后回表过滤剩余过滤条件。
  • MySQL 索引过滤:通过索引扫描并且基于索引进行二次条件过滤后再回表。

img

  • 使用索引下推实现

img

索引下推的使用条件

  • ICP目标是减少全行记录读取,从而减少IO 操作,只能用于非聚簇索引。聚簇索引本身包含的表数据,也就不存在下推一说。
  • 只能用于range、 ref、 eq_ref、ref_or_null访问方法;
  • where 条件中是用 and 而非 or 的时候。
  • ICP适用于分区表。
  • ICP不支持基于虚拟列上建立的索引,比如说函数索引
  • ICP不支持引用子查询作为条件。
  • ICP不支持存储函数作为条件,因为存储引擎无法调用存储函数。

索引下推相关语句:

# 查看索引下推是否开启
select @@optimizer_switch
# 开启索引下推
set optimizer_switch="index_condition_pushdown=on";
# 关闭索引下推
set optimizer_switch="index_condition_pushdown=off";

我们来进行具体的测试:

CREATE DATABASE icp_demo;
USE icp_demo;

CREATE TABLE employees (
    emp_id INT AUTO_INCREMENT PRIMARY KEY,
    emp_name VARCHAR(255),
    dept_id INT,
    salary DECIMAL(10, 2),
    hire_date DATE,
    INDEX idx_dept_salary (dept_id, salary)
) ENGINE=InnoDB;
DELIMITER $$
CREATE PROCEDURE populate_employees()
BEGIN
    DECLARE i INT DEFAULT 1;
    WHILE i <= 100000 DO
        INSERT INTO employees (emp_name, dept_id, salary, hire_date) 
        VALUES (
            CONCAT('Employee_', i), 
            FLOOR(RAND() * 10), 
            ROUND(RAND() * 100000, 2), 
            CURDATE() - INTERVAL FLOOR(RAND() * 3650) DAY
        );
        SET i = i + 1;
    END WHILE;
END$$
DELIMITER ;
CALL populate_employees();

在执行查询之前,我们可以先查看索引下推是否开启。

SELECT @@optimizer_switch;

image-20240822205816785

SET optimizer_switch = 'index_condition_pushdown=on';
EXPLAIN SELECT emp_id, emp_name FROM employees WHERE dept_id = 5 AND salary BETWEEN 50000 AND 80000;
SET optimizer_switch = 'index_condition_pushdown=off';
EXPLAIN SELECT emp_id, emp_name FROM employees WHERE dept_id = 5 AND salary BETWEEN 50000 AND 80000;

image-20240822210015283

记得再次打开:

SET optimizer_switch = 'index_condition_pushdown=on';
https://mp.weixin.qq.com/s?__biz=MzkwOTczNzUxMQ==&mid=2247484267&idx=1&sn=be0d6295a3992d13d76dc4d6c5b34ba6&chksm=c1376823f640e135895626711aadd115d0d40ff77a3f40157130b4199e4487b894414b5795be#rd

请添加图片描述

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

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

相关文章

打卡学习Python爬虫第五天|使用Xpath爬取豆瓣电影评分

思路&#xff1a;使用Xpath爬取豆瓣即将上映的电影评分&#xff0c;首先获取要爬取页面的url&#xff0c;查看页面源代码是否有我们想要的数据&#xff0c;如果有&#xff0c;直接获取HTML文件后解析HTML内容就能提取出我们想要的数据。如果没有则需要用到浏览器抓包工具&#…

基于x86 平台opencv的图像采集和seetaface6的人脸特征点功能

目录 一、概述二、环境要求2.1 硬件环境2.2 软件环境三、开发流程3.1 编写测试3.2 配置资源文件3.2 验证功能一、概述 本文档是针对x86 平台opencv的图像采集和seetaface6的人脸特征点功能,opencv通过摄像头采集视频图像,将采集的视频图像送给seetaface6的人脸特征点模块从而…

gif图片怎么压缩大小?深度测评7款动图压缩工具(内含教程)

gif图片在社交媒体和网络上非常流行&#xff0c;深受大家喜爱&#xff0c;因为它可以呈现生动的动画效果。gif动图之所以受到欢迎&#xff0c;主要因为其出色的压缩算法&#xff0c;能有效存储多个帧&#xff0c;从而实现流畅的动画。 然而&#xff0c;大多数社交媒体平台对gi…

《机器学习》决策树 C4.5算法、cart算法

一、什么是C4.5算法 1、概念 C4.5算法是一种决策树生成算法&#xff0c;它使用信息增益比&#xff08;gain ratio&#xff09;来选择最优分裂属性&#xff0c;它是ID3算法的改进版本。 C4.5算法的核心思想是选择信息增益比最大的特征作为节点进行划分&#xff0c;以获得最好的…

12.3.案例分析专题-面向对象设计

文章目录 面向对象分析与设计关系类图用例图包含 练习题2021年上真题2021年下真题 考点&#xff1a;用例图和类图 面向对象分析与设计 关系 依赖&#xff1a;一个事物的语义依赖于另一个事物的语义的变化而变化 关联&#xff1a;是一种结构关系&#xff0c;描述了一组链&#…

嵌入式C语言中函数宏基本操作方法

大家好,今天给大家分享一下,如何使用C语言中的函数宏,配置方法。 1 函数宏介绍 函数宏,即包含多条语句的宏定义,其通常为某一被频繁调用的功能的语句封装,且不想通过函数方式封装来降低额外的弹栈压栈开销。 函数宏本质上为宏,可以直接进行定义,例如: #define IN…

【后续更新】python搜集上海二手房数据

源码如下&#xff1a; import asyncio import aiohttp from lxml import etree import logging import datetime import openpyxlwb openpyxl.Workbook() sheet wb.active sheet.append([房源, 房子信息, 所在区域, 单价, 关注人数和发布时间, 标签]) logging.basicConfig(l…

华为账号“一键登录”能力让美团用户尽享安全便捷的登录体验

背景 随着全场景智能生态的日益完善&#xff0c;用户面临着众多应用与服务的登录需求&#xff0c; 而繁琐的注册登录流程通常是用户转化的隐形障碍&#xff0c;用户可能因为步骤繁琐、记忆密码困难而中途放弃&#xff0c;导致应用错失潜在用户。其次&#xff0c;高门槛的登录方…

Springcloud从零开始--Eureka(一)

Spring Cloud是一系列框架的有序集合。它利用Spring Boot的开发便利性巧妙地简化了分布式系统基础设施的开发&#xff0c;如服务发现注册、配置中心、消息总线、负载均衡、断路器、数据监控等&#xff0c;都可以用Spring Boot的开发风格做到一键启动和部署。Spring Cloud并没有…

Java数组06:冒泡排序

本节内容视频链接&#xff1a;Java数组08&#xff1a;冒泡排序_哔哩哔哩_bilibilihttps://www.bilibili.com/video/BV12J41137hu?p58&vd_sourceb5775c3a4ea16a5306db9c7c1c1486b5 冒泡排序是一种简单的排序算法&#xff0c;‌它重复地遍历要排序的数列&#xff0c;‌…

day37动态规划+三.Github链接本地仓库

一.动态规划 474.一和零 给你一个二进制字符串数组 strs 和两个整数 m 和 n 。 请你找出并返回 strs 的最大子集的长度&#xff0c;该子集中 最多 有 m 个 0 和 n 个 1 。 如果 x 的所有元素也是 y 的元素&#xff0c;集合 x 是集合 y 的 子集 。 思路:这道题更像是另一种的0-…

Linux编辑器gcc/g++使用及Vim的配置

&#x1f308;个人主页&#xff1a;Yui_ &#x1f308;Linux专栏&#xff1a;Linux &#x1f308;C语言笔记专栏&#xff1a;C语言笔记 &#x1f308;数据结构专栏&#xff1a;数据结构 &#x1f308;C专栏&#xff1a;C 文章目录 1.简单的vim配置1.1 配置文件的位置1.2 常用配…

20 Tkinter Spinbox 组件

Tkinter Spinbox 组件使用指南 Tkinter 的 Spinbox 组件是一个带有上下箭头的输入框&#xff0c;允许用户通过点击箭头来增加或减少数值&#xff0c;或者从下拉列表中选择一个值。它通常用于需要限制用户输入范围的场景。以下是对 Spinbox 组件的详细说明和一个使用案例。 Sp…

linux文件——用户缓冲区——概念深度探索、IO模拟实现

前言&#xff1a;本篇文章主要讲解文件缓冲区。 讲解的方式是通过抛出问题&#xff0c; 然后通过分析问题&#xff0c; 将缓冲区的概念与原理一步一步地讲解。同时&#xff0c; 本节内容在最后一部分还会带友友们模拟实现一下c语言的printf&#xff0c; fprintf接口&#xff0c…

前端面试题 webpack的工作流程

一、流程图 二、重要概念 1.entry入口&#xff1a; Webpack 从配置的入口点开始&#xff0c;分析应用程序的依赖关系 2.output出口&#xff1a; 定义了打包后的文件如何输出&#xff0c;包括文件名和输出路径。 3.loader加载器&#xff1a; Webpack 本身只能处理 JavaScr…

2024 Python3.10 系统入门+进阶(六):random模块常用方法以及元组常用操作详解

目录 一、random模块1.1 random模块快用导航1.2 choice()方法---从非空序列中返回一个随机元素1.3 choices()方法---返回序列的随机元素1.4 randint()方法---获取指定范围的随机整数1.5 random()方法---获取0.0~1.0范围内随机浮点数1.6 randrange()方法---获取指定范围的随机整…

ArcGIS Pro基础:如何将数据和引用地图样式一起打包分享

如上所示&#xff0c;有2个矢量图斑&#xff0c;一个是耕地地块&#xff0c;另一个是范围图斑&#xff0c;如果我们需要把此工程的所有数据以及引用地图一起分享给别人&#xff0c;就可以使用【打包工程】这个工具。 如上所示&#xff0c;在【地理处理】下输入【打包工程】&am…

Excel的使用总结1

目录 1、汇总公式&#xff1a;TEXTJOIN 2、excel中选择某个区域的方法 3、excel中如何在复制的时候&#xff0c;不将公式一起复制过去 4、想要自动填充某个区域的值的方法 1、汇总公式&#xff1a;TEXTJOIN TEXTJOIN 函数 - Microsoft 支持 例&#xff1a;TEXTJOIN("…

Java数组07:稀疏数组

本节内容视频链接&#xff1a; https://www.bilibili.com/video/BV12J41137hu?p59&vd_sourceb5775c3a4ea16a5306db9c7c1c1486b5https://www.bilibili.com/video/BV12J41137hu?p59&vd_sourceb5775c3a4ea16a5306db9c7c1c1486b5 稀疏数组&#xff08;‌sparse …

[SWPUCTF 2023 秋季新生赛]UnS3rialize

[SWPUCTF 2023 秋季新生赛]UnS3rialize 点开之后得到一串php代码&#xff1a; <?php highlight_file(__FILE__); error_reporting(0); class NSS {public $cmd;function __invoke(){echo "Congratulations!!!You have learned to construct a POP chain<br/>&q…