MySQL索引覆盖(覆盖索引, Covering Index)

embedded/2025/1/14 17:55:52/

文章目录

  • 说明
  • MySQL索引覆盖(覆盖索引, Covering Index)
    • 覆盖索引的概念
    • 覆盖索引的示例
    • 示例查询及索引覆盖情况
    • 覆盖索引的性能优势
    • 覆盖索引的实现条件
    • 覆盖索引 vs 非覆盖索引
    • 覆盖索引的限制
    • 如何设计覆盖索引
    • 覆盖索引的实际案例
      • 场景 1:电商系统中的订单查询
      • 场景 2:博客系统中的文章搜索
    • 总结

说明

  • 本文章内容由chatGpt4对话内容整理而来,如有错误之处,请在评论区留言!

MySQL索引覆盖(覆盖索引, Covering Index)

  • 索引覆盖 是指查询所需的所有列的数据都可以通过索引直接获取,而无需访问表中的实际数据行(即无需回表)。
  • 当查询满足索引覆盖的条件时,MySQL 可以只通过读取索引完成查询操作,从而显著提高查询性能。

覆盖索引的概念

  • 索引覆盖是指查询所涉及的字段(SELECT 的字段以及 WHERE、GROUP BY、ORDER BY 的字段)都被索引包含。如果查询中的所有字段都能从索引中获取,那么 MySQL 就可以直接在索引中返回结果,而不需要访问数据行。
  • 索引通常存储在一个更加紧凑的结构中,数据量较小,访问效率更高。避免了 “回表” 的开销(回表是指通过主键从聚簇索引或数据页中获取数据)。

覆盖索引的示例

假设有一个表 users

CREATE TABLE users (id INT PRIMARY KEY,         -- 主键name VARCHAR(50),           -- 用户名email VARCHAR(50),          -- 邮箱age INT,                    -- 年龄INDEX idx_name_email (name, email) -- 联合索引
);

示例查询及索引覆盖情况

  1. 索引覆盖的情况
    SELECT name, email FROM users WHERE name = 'Alice';
    
    • 索引 idx_name_email 包含 nameemail,查询的字段完全被索引覆盖。
    • MySQL 可以直接从索引中返回结果,无需访问实际表数据。
  2. 索引不覆盖的情况
    SELECT name, email, age FROM users WHERE name = 'Alice';
    
    • 索引 idx_name_email 包含了 nameemail,但不包含 age
    • 查询时,MySQL 会从索引中找到符合 name = 'Alice' 的记录,然后通过主键回表查找 age 字段。
  3. 索引部分使用的情况
    SELECT email FROM users WHERE name = 'Alice';
    
    • 查询使用索引 idx_name_emailname 列作为过滤条件,并获取email 列。这依然属于索引覆盖查询,因为所需的字段都在索引中。

覆盖索引的性能优势

  1. 减少 I/O 操作:索引通常比表数据小得多,且索引存储是紧凑的树形结构(例如 B+ 树),查询效率更高。如果可以直接从索引中获取数据,就不需要回表,大大减少磁盘 I/O。
  2. 提高查询速度:查询只在索引层完成,无需访问表的实际数据行。避免了读取大量不必要的表数据。
  3. 降低锁定范围:如果查询在索引中即可完成,可以减少对数据行的访问,从而降低行锁或表锁的影响。

覆盖索引的实现条件

  1. 必须有适当的索引
    • 覆盖索引依赖于索引的列包含了查询所需的所有字段。
    • 可以是单列索引,也可以是多列的联合索引。
  2. 选择性字段的优先设计
    • 查询中频繁用到的过滤条件(WHERE)或查询字段(SELECT)应优先设计为索引。
  3. InnoDB 表中的聚簇索引
    • InnoDB 存储引擎的主键索引是聚簇索引(clustered index),主键包含了实际行数据。
    • 如果查询字段只涉及主键索引,天然满足覆盖索引的条件。

覆盖索引 vs 非覆盖索引

特性覆盖索引非覆盖索引
是否回表无需回表,所有数据直接从索引中获取需要回表,从索引获取主键后再查找表数据
查询效率高,减少 I/O 操作较低,增加 I/O 操作
索引列要求查询字段必须全部在索引中查询字段不要求全部在索引中
常见场景多用于 SELECT 查询查询字段较多或数据更新频繁时更常见

覆盖索引的限制

  1. 查询字段必须包含在索引中:如果查询字段超出索引的覆盖范围,MySQL 必须回表获取缺失的数据。
  2. 索引过多会影响写性能:为了覆盖索引而创建大量的索引,可能会降低数据的写入速度,因为每次写操作都需要维护多个索引。
  3. 不支持全字段匹配模糊查询:如果查询条件涉及 LIKE '%xxx' 或非前缀模糊匹配的字段,覆盖索引无法发挥作用。
  4. 大字段类型的限制:索引中不适合存储大字段(如 TEXT、BLOB),这些字段通常不会被用于覆盖索引。

如何设计覆盖索引

  1. 常用查询字段优先索引
    • 优先为 WHERE、ORDER BY 和 SELECT 中频繁出现的字段建立索引。
    • 如果查询字段较少,可以通过适当调整索引覆盖范围来满足覆盖索引的条件。
  2. 联合索引优化:联合索引(多列索引)设计时,要注意字段顺序,优先将过滤条件的列放在前面。
  3. 避免过度索引:虽然覆盖索引可以提升查询性能,但索引维护的开销也需要考虑,过多的索引可能导致写性能下降。

覆盖索引的实际案例

场景 1:电商系统中的订单查询

表结构:

CREATE TABLE orders (order_id INT PRIMARY KEY,user_id INT NOT NULL,order_date DATE NOT NULL,total_amount DECIMAL(10, 2) NOT NULL,INDEX idx_user_date_amount (user_id, order_date, total_amount)
);

查询:

SELECT user_id, order_date, total_amount
FROM orders
WHERE user_id = 123 AND order_date >= '2023-01-01';

优化:

  • 索引 idx_user_date_amount 覆盖了所有查询字段。
  • 查询可直接从索引中返回结果,无需回表。

场景 2:博客系统中的文章搜索

表结构:

CREATE TABLE posts (post_id INT PRIMARY KEY,title VARCHAR(255),content TEXT,author_id INT,created_at DATETIME,INDEX idx_author_created (author_id, created_at)
);

查询:

SELECT author_id, created_at
FROM posts
WHERE author_id = 1 AND created_at > '2023-01-01';

优化:

  • 索引 idx_author_created 包含 author_idcreated_at
  • 查询字段被索引完全覆盖,可以通过覆盖索引加速查询。

总结

  • 覆盖索引 是 MySQL 中的一种性能优化技术,当查询所需的字段完全被索引覆盖时,MySQL 可以直接通过索引返回结果,避免回表操作。
  • 它的主要优势是 减少 I/O、提高查询速度,尤其适用于读操作较多的场景。
  • 设计覆盖索引时应结合实际查询需求,合理选择索引列,同时避免过多索引对写性能造成负面影响。

http://www.ppmy.cn/embedded/153599.html

相关文章

PyQt5按钮类控件Button

一、PushButton 开发中经常会用到的功能: 1.点击。 2.设置默认按钮。 3.设置按钮为可切换状态按钮。 1.方法 方法名称作用备注setText(QString)设置按钮上的文字,参数值为字符串text()获取按钮上的文字setIcon(QIcon)设置按钮icon&…

Elasticsearch(四)

Elasticsearch Java API 操作1.1 引入依赖1.2 客户端对象1.3 索引操作1.3.1 创建索引1.3.2 查看索引1.3.3 删除索引 1.4 文档操作1.4.1 新增文档1.4.2 修改文档1.4.3 查询文档1.4.4 删除文档1.4.5 批量新增1.4.6 批量删除 1.5 高级查询1.5.1 请求体查询1.5.1.1 查询所有索引数据…

网络安全-web渗透环境搭建-BWAPP(基础篇)

01--所需系统环境: 虚拟主机系统部署(vmware,虚拟主机创建、虚拟主机网络配置(桥接,便于网络中多个主机都能访问虚拟主机)、虚拟软件功能,快照、克隆、镜像文件加载,ova文件制作&am…

STM32如何测量运行的时钟频率

前言 环境: 芯片:STM32F103C8T6 Keil:V5.24.2.0 一、简介STM32F103C8T6的时钟源 ①HSI 内部高速时钟,RC振荡器,频率为8MHz,精度不高。②HSE 外部高速时钟,可接石英/陶瓷谐振器,频率范围为4MHz~16MHz&…

Spring Framework 5.3.x源码构建 (jdk-1.8, gradle 7.5.1, idea2024.3)

1、下载jdk安装并配置环境变量(自行百度) https://www.oracle.com/java/technologies/downloads/#java8 2、下载spring-framework源码,切换分支到5.3.x https://github.com/spring-projects/spring-framework.git 备用地址 https://gitco…

MySQL教程之:常见查询示例

下面举例说明如何用MySQL解决一些常见问题。 一些示例使用表shop来保存某些交易者(经销商)的每件商品的价格(商品编号)。假设每个交易者每件商品都有一个固定的价格,那么(article,dealer&#…

leetcode-------mysql

SQL 面试宝典 10. 人口流动分析 - 力扣(LeetCode) 表: 各城市人口流动表 ---------------------- | 字段名称 | 类型 | ---------------------- | 流出城市 | varchar | | 流入城市 | varchar | | 交通工具 | int | | 日期 …

从预训练的BERT中提取Embedding

文章目录 背景前置准备思路利用Transformer 库实现 背景 假设要执行一项情感分析任务,样本数据如下 可以看到几个句子及其对应的标签,其中1表示正面情绪,0表示负面情绪。我们可以利用给定的数据集训练一个分类器,对句子所表达的…