MySQL(55)什么是覆盖索引?

覆盖索引(Covering Index)是一种特殊类型的索引,其中查询所需的所有列都包含在索引中。这意味着数据库可以完全从索引中读取数据,而不必访问表,从而显著提高查询性能。

覆盖索引的优点

  1. 减少I/O操作:通过从索引中直接读取数据,可以减少对表的访问次数,从而减少I/O操作。
  2. 提高查询速度:由于索引通常比表更小,遍历索引通常比遍历表更快。
  3. 减少页读取次数:覆盖索引可以减少数据库需要读取的页数,从而提升查询性能。

1. 示例表结构

假设有一个名为 employees 的表,用于存储员工信息:

sql 复制代码
CREATE TABLE employees (
    emp_id INT AUTO_INCREMENT PRIMARY KEY,
    emp_name VARCHAR(100),
    department_id INT,
    salary DECIMAL(10, 2),
    hire_date DATE
);

2. 创建覆盖索引

假设我们有一个常见的查询需求,查询员工的姓名和工资,条件是部门ID为2:

sql 复制代码
SELECT emp_name, salary FROM employees WHERE department_id = 2;

为了使这个查询使用覆盖索引,我们可以创建一个包含所有查询字段的复合索引:

sql 复制代码
CREATE INDEX idx_covering_emp ON employees(department_id, emp_name, salary);

3. 使用 EXPLAIN 验证覆盖索引

使用 EXPLAIN 分析查询的执行计划,验证是否使用了覆盖索引:

sql 复制代码
EXPLAIN SELECT emp_name, salary FROM employees WHERE department_id = 2;

假设 EXPLAIN 的输出如下:

plaintext 复制代码
+----+-------------+----------+------------+-------+------------------+-------------------+---------+-------+------+----------+-------------+
| id | select_type | table    | partitions | type  | possible_keys    | key               | key_len | ref   | rows | filtered | Extra       |
+----+-------------+----------+------------+-------+------------------+-------------------+---------+-------+------+----------+-------------+
|  1 | SIMPLE      | employees| NULL       | ref   | idx_covering_emp | idx_covering_emp  | 4       | const | 100  |   100.00 | Using index |
+----+-------------+----------+------------+-------+------------------+-------------------+---------+-------+------+----------+-------------+

Extra 列中,Using index 表示查询使用了覆盖索引,意味着查询的数据完全从索引中读取,无需访问表。

4. 示例分析

让我们详细分析如何使用覆盖索引提高查询性能。

示例查询1

查询特定部门的员工姓名和工资:

sql 复制代码
SELECT emp_name, salary FROM employees WHERE department_id = 2;

通过创建覆盖索引 idx_covering_emp 可以显著提高这个查询的性能。

示例查询2

查询特定部门的员工详细信息:

sql 复制代码
SELECT emp_name, salary, hire_date FROM employees WHERE department_id = 2;

为了使这个查询使用覆盖索引,需要修改覆盖索引以包含所有查询字段:

sql 复制代码
CREATE INDEX idx_covering_emp_full ON employees(department_id, emp_name, salary, hire_date);

5. 比较覆盖索引和普通索引

普通索引示例

仅在 department_id 列上创建索引:

sql 复制代码
CREATE INDEX idx_department_id ON employees(department_id);

查询:

sql 复制代码
SELECT emp_name, salary FROM employees WHERE department_id = 2;

使用 EXPLAIN 分析:

plaintext 复制代码
+----+-------------+----------+------------+------+------------------+-------------------+---------+-------+------+----------+-------------+
| id | select_type | table    | partitions | type | possible_keys    | key               | key_len | ref   | rows | filtered | Extra       |
+----+-------------+----------+------------+------+------------------+-------------------+---------+-------+------+----------+-------------+
|  1 | SIMPLE      | employees| NULL       | ref  | idx_department_id| idx_department_id | 4       | const | 100  |   100.00 | Using where |
+----+-------------+----------+------------+------+------------------+-------------------+---------+-------+------+----------+-------------+

这种情况下,查询需要访问表数据来获取 emp_namesalary 列,因此性能较差。

覆盖索引示例

创建覆盖索引:

sql 复制代码
CREATE INDEX idx_covering_emp ON employees(department_id, emp_name, salary);

查询:

sql 复制代码
SELECT emp_name, salary FROM employees WHERE department_id = 2;

使用 EXPLAIN 分析:

plaintext 复制代码
+----+-------------+----------+------------+-------+------------------+-------------------+---------+-------+------+----------+-------------+
| id | select_type | table    | partitions | type  | possible_keys    | key               | key_len | ref   | rows | filtered | Extra       |
+----+-------------+----------+------------+-------+------------------+-------------------+---------+-------+------+----------+-------------+
|  1 | SIMPLE      | employees| NULL       | ref   | idx_covering_emp | idx_covering_emp  | 4       | const | 100  |   100.00 | Using index |
+----+-------------+----------+------------+-------+------------------+-------------------+---------+-------+------+----------+-------------+

此时,查询使用覆盖索引,可以直接从索引中获取所有需要的数据,性能更高。

6. 覆盖索引的局限性

尽管覆盖索引可以显著提高查询性能,但它们也有一些局限性:

  1. 需要更多存储空间:覆盖索引包含所有查询列,因此会占用更多存储空间。
  2. 维护开销:每次插入、更新和删除操作都需要更新覆盖索引,增加了维护开销。
  3. 索引大小限制:覆盖索引不适用于包含大量列的大型表,因为索引大小受限。

7. 覆盖索引的最佳实践

  1. 选择性高的列:将选择性高的列放在索引的前面,以最大化查询性能。
  2. 合理选择覆盖索引:仅为频繁查询且需要高性能的查询创建覆盖索引。
  3. 定期维护索引:定期重建和分析覆盖索引,以确保其高效性。

小结

覆盖索引是一种强大的优化工具,可以显著提高查询性能,尤其是在需要频繁访问特定列的情况下。通过合理设计和使用覆盖索引,可以减少I/O操作,提高查询速度,提升数据库的整体性能。然而,覆盖索引也需要权衡存储空间和维护开销,在实际应用中需要根据具体需求和数据特点进行合理规划和使用。

相关推荐
yuren_xia2 小时前
Spring Boot中保存前端上传的图片
前端·spring boot·后端
JohnYan5 小时前
Bun技术评估 - 04 HTTP Client
javascript·后端·bun
shangjg35 小时前
Kafka 的 ISR 机制深度解析:保障数据可靠性的核心防线
java·后端·kafka
青莳吖6 小时前
使用 SseEmitter 实现 Spring Boot 后端的流式传输和前端的数据接收
前端·spring boot·后端
我的golang之路果然有问题7 小时前
ElasticSearch+Gin+Gorm简单示例
大数据·开发语言·后端·elasticsearch·搜索引擎·golang·gin
mldong8 小时前
我的全栈工程师之路:全栈学习路线分享
前端·后端
噼里啪啦啦.9 小时前
SpringBoot统一功能处理
java·spring boot·后端
考虑考虑9 小时前
JPA自定义sql参数为空和postgresql遇到问题
spring boot·后端·spring
橘子青衫10 小时前
Java多线程编程:深入探索线程同步与互斥的实战策略
java·后端·性能优化
shengjk110 小时前
一文搞懂 python __init__.py 文件
后端