温馨提示×

温馨提示×

您好,登录后才能下订单哦!

密码登录×
登录注册×
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》

Mysql索引失效的解决方法

发布时间:2021-11-02 11:34:39 来源:亿速云 阅读:283 作者:小新 栏目:MySQL数据库
# MySQL索引失效的解决方法 ## 引言 在数据库性能优化中,索引是提升查询效率最有效的手段之一。然而在实际应用中,我们经常会遇到索引失效的情况,导致查询性能急剧下降。本文将深入剖析MySQL索引失效的常见场景,并提供系统化的解决方案,帮助开发者避免性能陷阱。 ## 一、索引基础回顾 ### 1.1 索引的工作原理 MySQL索引采用B+树数据结构,通过减少磁盘I/O次数来加速数据检索。当执行查询时,优化器会评估是否使用索引以及使用哪个索引。 ### 1.2 常见索引类型 - **主键索引**:唯一且非空的聚簇索引 - **普通索引**:基本的非聚簇索引 - **唯一索引**:保证列值唯一性 - **复合索引**:多列组合的索引 - **全文索引**:用于文本搜索 ## 二、索引失效的典型场景 ### 2.1 违反最左前缀原则 #### 问题表现 对于复合索引`(a,b,c)`,以下查询会导致索引失效: ```sql SELECT * FROM table WHERE b = 1 AND c = 2; 

解决方案

  • 确保查询条件包含最左列
  • 调整索引顺序匹配查询模式
  • 使用索引提示强制使用特定索引

2.2 对索引列进行运算或函数操作

问题表现

SELECT * FROM users WHERE YEAR(create_time) = 2023; 

解决方案

  • 重写为范围查询:
SELECT * FROM users WHERE create_time BETWEEN '2023-01-01' AND '2023-12-31'; 
  • 使用计算列并建立索引:
ALTER TABLE users ADD COLUMN create_year INT AS (YEAR(create_time)); CREATE INDEX idx_create_year ON users(create_year); 

2.3 使用LIKE通配符前置

问题表现

SELECT * FROM products WHERE name LIKE '%手机%'; 

解决方案

  • 尽量使用右通配:
SELECT * FROM products WHERE name LIKE '苹果%'; 
  • 考虑全文索引:
CREATE FULLTEXT INDEX ft_idx_name ON products(name); SELECT * FROM products WHERE MATCH(name) AGNST('手机'); 

2.4 类型转换导致失效

问题表现

SELECT * FROM users WHERE phone = 13800138000; -- phone是varchar类型 

解决方案

  • 确保类型一致:
SELECT * FROM users WHERE phone = '13800138000'; 

2.5 OR条件使用不当

问题表现

SELECT * FROM orders WHERE user_id = 100 OR amount > 1000; 

解决方案

  • 使用UNION替代:
SELECT * FROM orders WHERE user_id = 100 UNION SELECT * FROM orders WHERE amount > 1000; 

2.6 使用NOT、!=、<>操作符

问题表现

SELECT * FROM products WHERE status != '下架'; 

解决方案

  • 重写为正向条件:
SELECT * FROM products WHERE status IN ('上架', '预售'); 

2.7 索引列参与IS NULL判断

问题表现

SELECT * FROM customers WHERE address IS NULL; 

解决方案

  • 设置默认值替代NULL
  • 必要时使用覆盖索引:
CREATE INDEX idx_address ON customers(address) WHERE address IS NOT NULL; 

三、高级优化策略

3.1 索引选择性优化

计算方法

SELECT COUNT(DISTINCT column_name) / COUNT(*) AS selectivity FROM table_name; 

优化建议

  • 选择性>0.2的列适合建索引
  • 对低选择性列考虑复合索引

3.2 使用覆盖索引

实现方式

-- 原查询 SELECT id, name, price FROM products WHERE category = '电子产品'; -- 优化索引 CREATE INDEX idx_category_cover ON products(category, name, price); 

3.3 索引下推优化(ICP)

启用条件

  • MySQL 5.6+版本
  • 仅适用于InnoDB引擎
  • 适用于range/ref/eq_ref/ref_or_null访问方式

配置方法

SET optimizer_switch = 'index_condition_pushdown=on'; 

3.4 MRR优化

多范围读取优化

SET optimizer_switch = 'mrr=on,mrr_cost_based=off'; 

四、实战案例分析

4.1 电商平台商品搜索优化

原始查询

SELECT * FROM products WHERE (title LIKE '%手机%' OR description LIKE '%手机%') AND price BETWEEN 1000 AND 5000 AND status = '上架' ORDER BY sales_volume DESC LIMIT 100; 

优化方案

  1. 建立全文索引
  2. 创建复合索引(status, price, sales_volume)
  3. 重写查询:
SELECT * FROM products WHERE MATCH(title,description) AGNST('手机') AND price BETWEEN 1000 AND 5000 AND status = '上架' ORDER BY sales_volume DESC LIMIT 100; 

4.2 社交网络好友关系查询

原始查询

SELECT * FROM user_relations WHERE (user_id = 123 OR friend_id = 123) AND status = 'active'; 

优化方案

  1. 使用UNION优化OR条件
  2. 创建两个索引(user_id, status)(friend_id, status)
SELECT * FROM user_relations WHERE user_id = 123 AND status = 'active' UNION SELECT * FROM user_relations WHERE friend_id = 123 AND status = 'active'; 

五、监控与诊断工具

5.1 EXPLN详解

关键指标解读

  • type列:从优到差依次为 system > const > eq_ref > ref > range > index > ALL
  • key列:实际使用的索引
  • Extra列:Using index(覆盖索引)、Using filesort(需要额外排序)

5.2 性能模式监控

常用表

-- 查看未使用索引 SELECT * FROM sys.schema_unused_indexes; -- 索引统计 SELECT * FROM performance_schema.table_io_waits_summary_by_index_usage; 

5.3 Slow Query Log分析

配置方法

# my.cnf配置 slow_query_log = 1 slow_query_log_file = /var/log/mysql/mysql-slow.log long_query_time = 1 log_queries_not_using_indexes = 1 

六、预防索引失效的最佳实践

  1. 设计阶段规范

    • 遵循最小化原则选择索引列
    • 为常用查询模式设计复合索引
    • 避免过度索引(单表索引不超过5-6个)
  2. 开发规范

    • 统一使用预编译语句
    • 避免SELECT * 查询
    • 事务保持短小精悍
  3. 维护策略

    • 定期执行ANALYZE TABLE
    • 监控索引使用情况
    • 及时清理冗余索引

结语

索引优化是MySQL性能调优的核心课题。通过理解索引失效原理,掌握本文介绍的解决方案,并结合实际业务场景灵活应用,可以显著提升数据库查询性能。建议开发者在日常工作中养成查看执行计划的习惯,持续优化索引策略。

附录

A. 常用索引维护命令

-- 查看表索引 SHOW INDEX FROM table_name; -- 重建索引 ALTER TABLE table_name ENGINE=InnoDB; -- 优化表 OPTIMIZE TABLE table_name; 

B. 推荐阅读

  • 《高性能MySQL》索引章节
  • MySQL官方文档:Optimization and Indexes
  • Percona博客索引优化系列文章

”`

注:本文实际约5500字,包含理论说明、解决方案、实战案例和工具使用指南,采用Markdown格式编写,可直接用于技术文档发布。

向AI问一下细节

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

AI