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

相关推荐
魔尔助理顾问3 小时前
系统整理Python的循环语句和常用方法
开发语言·后端·python
程序视点3 小时前
Java BigDecimal详解:小数精确计算、使用方法与常见问题解决方案
java·后端
你的人类朋友3 小时前
❤️‍🔥微服务的拆分策略
后端·微服务·架构
AI小智5 小时前
后端变全栈,终于可以给大家推出我的LangChain学习小站了!
后端
lkf197115 小时前
商品中心—1.B端建品和C端缓存
开发语言·后端·缓存
我的ID配享太庙呀6 小时前
Django 科普介绍:从入门到了解其核心魅力
数据库·后端·python·mysql·django·sqlite
java叶新东老师6 小时前
goland编写go语言导入自定义包出现: package xxx is not in GOROOT (/xxx/xxx) 的解决方案
开发语言·后端·golang
码事漫谈8 小时前
C++模板元编程从入门到精通
后端
_風箏8 小时前
Java【代码 14】一个用于判断磁盘空间和分区表是否需要清理的工具类
后端
_風箏8 小时前
Java【代码 13】前端动态添加一条记后端使用JDK1.8实现map对象根据key的部分值进行分组(将map对象封装成指定entity对象)
后端