1. 首页 > MySQL教程 > 正文

MySQL教程FG084-MySQL索引失效场景分析

内容简介:本文主要介绍MySQL相关知识,包括安装、配置、优化等内容。风哥教程参考MySQL官方文档MySQL SQL Syntax、MySQL Server Administration。 01 更多视频教程www.fgedu.net.cn 02 学习交流加群风哥微信: itpux-com

Part01-基础概念与理论知识

索引是提高MySQL查询性能的重要工具,但在某些情况下,索引可能会失效,导致查询性能下降。了解索引失效的场景和原因,对于优化数据库性能至关重要。本文将详细分析MySQL中索引失效的常见场景,以及如何避免这些问题。 03 学习交流加群风哥QQ113257174

Part02-生产环境规划与建议

2.1 索引列上使用函数

-- 索引列上使用函数,导致索引失效
SELECT * FROM employees WHERE YEAR(hire_date) = 2023;

-- 优化后:使用范围查询,利用索引
SELECT * FROM employees WHERE hire_date BETWEEN '2023-01-01' AND '2023-12-31';

2.2 索引列上进行计算

-- 索引列上进行计算,导致索引失效
SELECT * FROM products WHERE price * 0.8 < 1000;

-- 优化后:将计算移到右侧
SELECT * FROM products WHERE price < 1000 / 0.8;

2.3 索引列上使用不等于操作符

-- 使用不等于操作符,可能导致索引失效
SELECT * FROM employees WHERE salary != 10000;

-- 优化后:如果必须使用不等于,可以考虑使用UNION
SELECT * FROM employees WHERE salary < 10000
UNION
SELECT * FROM employees WHERE salary > 10000;

2.4 索引列上使用LIKE操作符(以通配符开头)

-- LIKE以通配符开头,导致索引失效
SELECT * FROM employees WHERE name LIKE '%风哥1号%';

-- 优化后:如果必须使用LIKE,可以考虑使用全文索引
SELECT * FROM employees WHERE MATCH(name) AGAINST('风哥1号');

2.5 索引列上使用IS NULL或IS NOT NULL

-- 使用IS NULL或IS NOT NULL,可能导致索引失效
SELECT * FROM employees WHERE department_id IS NULL;

-- 优化后:考虑在应用层面处理,或者使用默认值代替NULL

2.6 复合索引不遵循最左前缀原则

-- 复合索引为(department_id, salary),但查询只使用了salary
SELECT * FROM employees WHERE salary > 10000;

-- 优化后:要么添加单独的salary索引,要么在查询中包含department_id
SELECT * FROM employees WHERE department_id = 1 AND salary > 10000;

2.7 索引列类型不匹配

-- 索引列是INT类型,但查询使用了字符串
SELECT * FROM employees WHERE id = '1';

-- 优化后:使用正确的类型
SELECT * FROM employees WHERE id = 1;

2.8 索引列上使用OR操作符

-- 使用OR操作符,可能导致索引失效
SELECT * FROM employees WHERE department_id = 1 OR salary > 10000;

-- 优化后:使用UNION
SELECT * FROM employees WHERE department_id = 1
UNION
SELECT * FROM employees WHERE salary > 10000;

Part03-生产环境项目实施方案

3.1 场景1:函数操作导致索引失效

SQL语句 是否使用索引 原因 优化方案
SELECT * FROM employees WHERE YEAR(hire_date) = 2023 索引列上使用了YEAR函数 使用范围查询:WHERE hire_date BETWEEN '2023-01-01' AND '2023-12-31'
SELECT * FROM employees WHERE LOWER(name) = 'zhangsan' 索引列上使用了LOWER函数 存储数据时统一大小写,或使用大小写不敏感的排序规则
SELECT * FROM employees WHERE SUBSTRING(name, 1, 2) = '张' 索引列上使用了SUBSTRING函数 使用前缀索引或全文索引

3.2 场景2:计算操作导致索引失效

SQL语句 是否使用索引 原因 优化方案
SELECT * FROM products WHERE price * 0.8 < 1000 索引列上进行了计算 将计算移到右侧:WHERE price < 1000 / 0.8
SELECT * FROM employees WHERE salary + 1000 > 10000 索引列上进行了计算 将计算移到右侧:WHERE salary > 9000

3.3 场景3:LIKE操作导致索引失效

SQL语句 是否使用索引 原因 优化方案
SELECT * FROM employees WHERE name LIKE '%风哥1号%' LIKE以通配符开头 使用全文索引或应用层面处理
SELECT * FROM employees WHERE name LIKE '风哥1号%' LIKE以固定字符开头 无需优化

3.4 场景4:复合索引不遵循最左前缀原则

SQL语句 是否使用索引 原因 优化方案
SELECT * FROM employees WHERE department_id = 1 AND salary > 10000 遵循最左前缀原则 无需优化
SELECT * FROM employees WHERE department_id = 1 遵循最左前缀原则 无需优化
SELECT * FROM employees WHERE salary > 10000 不遵循最左前缀原则 添加单独的salary索引

3.5 场景5:OR操作导致索引失效

SQL语句 是否使用索引 原因 优化方案
SELECT * FROM employees WHERE department_id = 1 OR salary > 10000 OR操作可能导致索引失效 使用UNION
SELECT * FROM employees WHERE department_id = 1 OR department_id = 2 OR操作的列是同一个索引列 无需优化,或使用IN:WHERE department_id IN (1, 2)

Part04-生产案例与实战讲解

4.1 避免在索引列上使用函数

  • 将函数操作转换为范围查询
  • 在应用层面处理函数操作
  • 考虑使用生成列(Generated Columns)

4.2 避免在索引列上进行计算

  • 将计算移到查询条件的右侧
  • 在应用层面进行计算
  • 考虑使用生成列

4.3 合理使用LIKE操作符

  • 尽量使用前缀匹配(如'风哥1号%')
  • 对于全匹配,考虑使用全文索引
  • 避免使用'%风哥1号%'这样的模式

4.4 遵循复合索引的最左前缀原则

  • 根据查询顺序设计复合索引
  • 确保查询条件包含复合索引的最左列
  • 对于频繁使用的单列查询,考虑添加单独的索引

4.5 确保索引列类型匹配

  • 使用正确的数据类型进行查询
  • 避免隐式类型转换

4.6 合理使用OR操作符

  • 对于不同列的OR操作,考虑使用UNION
  • 对于同一列的OR操作,使用IN代替

Part05-风哥经验总结与分享

5.1 使用EXPLAIN分析执行计划

-- 分析查询执行计划
EXPLAIN SELECT * FROM employees WHERE YEAR(hire_date) = 2023;

-- 查看key列是否有值,如果为NULL则表示没有使用索引

5.2 查看慢查询日志

-- 启用慢查询日志
SET GLOBAL slow_query_log = ON;
SET GLOBAL long_query_time = 1;

-- 查看慢查询日志中的SQL语句,分析是否使用了索引

5.3 监控索引使用情况

-- 启用性能模式
SET GLOBAL performance_schema = ON;

-- 查看索引使用情况
SELECT 
    object_schema, 
    object_name, 
    index_name, 
    count_star AS access_count 
FROM 
    performance_schema.table_io_waits_summary_by_index_usage 
WHERE 
    object_schema = 'your_database' 
ORDER BY 
    access_count DESC;

6. 实际案例分析

6.1 案例1:函数操作导致索引失效

-- 原查询:索引失效
SELECT * FROM orders WHERE DATE(created_at) = '2023-01-01';

-- 优化后:使用索引
SELECT * FROM orders WHERE created_at BETWEEN '2023-01-01 00:00:00' AND '2023-01-01 23:59:59';

6.2 案例2:LIKE操作导致索引失效

-- 原查询:索引失效
SELECT * FROM products WHERE name LIKE '%手机%';

-- 优化后:使用全文索引
ALTER TABLE products ADD FULLTEXT INDEX idx_products_name(name);
SELECT * FROM products WHERE MATCH(name) AGAINST('手机');

6.3 案例3:复合索引不遵循最左前缀原则

-- 原查询:索引失效
SELECT * FROM employees WHERE salary > 10000;

-- 优化后:添加单独的索引
CREATE INDEX idx_employees_salary ON employees(salary);
SELECT * FROM employees WHERE salary > 10000;

6.4 案例4:OR操作导致索引失效

-- 原查询:索引失效
SELECT * FROM employees WHERE department_id = 1 OR salary > 10000;

-- 优化后:使用UNION
SELECT * FROM employees WHERE department_id = 1
UNION
SELECT * FROM employees WHERE salary > 10000;

7. 索引失效的特殊情况

7.1 索引覆盖

-- 即使使用了函数,如果查询的列都在索引中,也会使用索引(索引覆盖)
-- 假设有索引(idx_name) on employees(name)
SELECT name FROM employees WHERE LOWER(name) = 'zhangsan';
-- 虽然使用了LOWER函数,但由于只查询name列,会使用索引覆盖

7.2 索引统计信息不准确

-- 索引统计信息不准确可能导致优化器选择不使用索引
-- 更新索引统计信息
ANALYZE TABLE employees;

7.3 数据分布不均匀

-- 如果数据分布不均匀,优化器可能认为全表扫描比使用索引更快
-- 例如,某列90%的值都是相同的,优化器可能选择全表扫描

8. 总结

索引失效是MySQL查询性能下降的常见原因之一。本文详细分析了MySQL中索引失效的各种场景,包括函数操作、计算操作、LIKE操作、复合索引使用不当等。通过了解这些场景和原因,我们可以采取相应的措施来避免索引失效,提高查询性能。 04 风哥提示:

在实际应用中,应该注意以下几点: 05更多学习教程公众号风哥教程itpux_com

  • 避免在索引列上使用函数和计算操作
  • 合理使用LIKE操作符,避免以通配符开头
  • 遵循复合索引的最左前缀原则
  • 确保索引列类型匹配
  • 合理使用OR操作符,必要时使用UNION代替
  • 定期使用EXPLAIN分析查询执行计划
  • 监控索引使用情况,及时调整索引结构

通过遵循这些最佳实践,可以有效避免索引失效,提高MySQL查询性能,确保应用系统的高效运行。 06 from mysql视频:www.itpux.com

GF-MySQL数据库培训文档系列

本文由风哥教程整理发布,仅用于学习测试使用,转载注明出处:http://www.fgedu.net.cn/10327.html

联系我们

在线咨询:点击这里给我发消息

微信号:itpux-com

工作日:9:30-18:30,节假日休息