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操作,提高查询速度,提升数据库的整体性能。然而,覆盖索引也需要权衡存储空间和维护开销,在实际应用中需要根据具体需求和数据特点进行合理规划和使用。

相关推荐
雷渊17 分钟前
微服务中为什么要设计不同的服务和不同的数据对象,体现了一个什么样的设计思想?
后端
无奈何杨1 小时前
CoolGuard风控中新增移动距离和移动速度指标
前端·后端
程序员爱钓鱼1 小时前
Go语言泛型-泛型约束与实践
前端·后端·go
寻月隐君1 小时前
保姆级教程:Zsh + Oh My Zsh 终极配置,让你的 Ubuntu 终端效率倍增
linux·后端·命令行
程序员爱钓鱼1 小时前
Go语言泛型-泛型对代码结构的优化
后端·google·go
这里有鱼汤1 小时前
“对象”?对象你个头!——Python世界观彻底崩塌的一天
后端·python
RainbowSea1 小时前
跨域问题(Allow CORS)解决(3 种方法)
java·spring boot·后端
sniper_fandc3 小时前
SpringBoot系列—入门
java·spring boot·后端
Piper蛋窝9 小时前
深入 Go 语言垃圾回收:从原理到内建类型 Slice、Map 的陷阱以及为何需要 strings.Builder
后端·go
六毛的毛12 小时前
Springboot开发常见注解一览
java·spring boot·后端