当前位置: 首页 > news >正文

详解MYSQL索引失效问题排查

目录

一、快速定位索引失效的步骤

1. 使用 EXPLAIN 分析执行计划详解Mysql的Explain语句

2. 确认索引是否存在

3. 检查查询条件是否符合索引规则

二、常见索引失效场景及解决方法 

1. 索引列参与计算或函数

2. 隐式类型转换

3. 使用 LIKE 以通配符开头

4. 使用 OR 连接非索引列 

5. 索引选择性过低

6. 联合索引顺序错误

7. 使用 != 或 <> 操作符

8. IS NULL 或 IS NOT NULL 条件

9. 多个索引ORDER BY 顺序不一致

10.  全文索引的误用

三、高级排查工具

1. 开启慢查询日志

2. 使用 OPTIMIZER_TRACE 分析优化器决策

3. 强制使用索引测试

四、总结


一、快速定位索引失效的步骤

1. 使用 EXPLAIN 分析执行计划详解Mysql的Explain语句

EXPLAIN SELECT * FROM users WHERE age = 25 AND name = 'John';

重点关注以下字段:

  • type:若显示 ALL(全表扫描)或 index(全索引扫描),可能索引未生效。

  • key:实际使用的索引名称,若为 NULL 表示未使用索引。

  • rows:预估扫描的行数,数值过大说明索引可能未生效。

  • Extra:若出现 Using filesort 或 Using temporary,可能索引未被用于排序或分组。

2. 确认索引是否存在

SHOW INDEX FROM users;  -- 查看表的索引信息

确保查询涉及的列(尤其是 WHEREJOINORDER BY 中的列)已创建索引。

3. 检查查询条件是否符合索引规则

  • 最左前缀原则:联合索引 (a, b, c) 必须按顺序使用,跳过中间列会导致后续列无法使用索引。

    WHERE a=1 AND c=3;  -- 仅使用到 a 列的索引,c 列无法生效
  • 范围查询阻断索引:范围查询(><BETWEEN)后的列无法使用索引。

    WHERE a>10 AND b=20;  -- 仅 a 列使用索引,b 列无法生效

二、常见索引失效场景及解决方法 

1. 索引列参与计算或函数

  • 失效示例

    SELECT * FROM users WHERE YEAR(create_time) = 2023;  -- 对索引列使用函数
    SELECT * FROM users WHERE age + 10 > 30;            -- 对索引列进行运算
  • 优化方法:改写为直接使用索引列。

    SELECT * FROM users WHERE create_time BETWEEN '2023-01-01' AND '2023-12-31';

2. 隐式类型转换

  • 失效示例

    -- 假设 phone 是 VARCHAR 类型,但传入数字
    SELECT * FROM users WHERE phone = 13800138000;  -- 字符串转数字导致索引失效
  • 优化方法:确保数据类型一致。

    SELECT * FROM users WHERE phone = '13800138000';

3. 使用 LIKE 以通配符开头

  • 失效示例

    SELECT * FROM users WHERE name LIKE '%John%';  -- 前导通配符导致索引失效
  • 优化方法:尽量使用右通配符。

    SELECT * FROM users WHERE name LIKE 'John%';  -- 可能使用索引

4. 使用 OR 连接非索引列 

  • 失效示例

    -- 假设 age 有索引,address 无索引
    SELECT * FROM users WHERE age = 25 OR address = 'Beijing';  -- 全表扫描
  • 优化方法:改用 UNION 拆分查询。

    SELECT * FROM users WHERE age = 25 
    UNION 
    SELECT * FROM users WHERE address = 'Beijing';

5. 索引选择性过低

  • 问题现象:索引列的值重复率过高(如性别字段),MySQL 可能放弃使用索引。

  • 优化方法:删除低选择性索引,或结合其他列创建联合索引。

    ALTER TABLE users ADD INDEX idx_gender_age (gender, age);

6. 联合索引顺序错误

  • 问题现象:联合索引 (a, b, c),但查询未按最左前缀顺序使用,导致索引部分失效。

  • 失效示例

    -- 索引 (a, b, c)
    SELECT * FROM table WHERE b = 2 AND a = 1;  -- 正常使用索引(优化器自动调整顺序)
    SELECT * FROM table WHERE a = 1 AND c = 3;  -- 仅用到 a 列索引,c 未生效
    SELECT * FROM table WHERE b = 2;            -- 索引完全失效(未使用最左列 a)
  • 优化方法

    • 调整查询条件顺序,确保按最左前缀匹配。

    • 根据高频查询场景,设计合理的联合索引顺序。

7. 使用 != 或 <> 操作符

  • 问题现象:非等值查询(如 !=NOT IN)可能导致索引失效。

  • 失效示例

    SELECT * FROM users WHERE age != 25;       -- 可能全表扫描
    SELECT * FROM orders WHERE status NOT IN (1, 2);  
  • 优化方法

    • 改写为等值查询或范围查询:

      SELECT * FROM users WHERE age < 25 OR age > 25;  -- 仍可能失效,需结合其他条件
    • 若数据分布倾斜,强制使用索引(需测试验证):

      SELECT * FROM users FORCE INDEX(idx_age) WHERE age != 25;

8. IS NULL 或 IS NOT NULL 条件

  •  问题现象:索引列上使用 IS NULL 或 IS NOT NULL 可能导致索引失效。

  • 失效示例

    SELECT * FROM users WHERE phone IS NULL;      -- 可能全表扫描
  • 优化方法:若 NULL 值较少,添加条件冗余字段:

    ALTER TABLE users ADD COLUMN is_phone_null TINYINT(1) DEFAULT 0;
    CREATE INDEX idx_phone_null ON users(is_phone_null);
    SELECT * FROM users WHERE is_phone_null = 1;

    9. 多个索引ORDER BY 顺序不一致

    •  问题现象:排序字段顺序与索引顺序不匹配,导致无法利用索引排序。

    • 失效示例

      -- 索引 (a, b)
      SELECT * FROM table WHER ORDER BY a ASC, b DESC;  -- 2个索引顺序不一致导致失效
      
    • 优化方法:调整联合索引顺序,同升同降。

      SELECT * FROM table WHER ORDER BY a ASC, b ASC;  同升同降
      

    10.  全文索引的误用

    •  问题现象:错误使用 LIKE 或 MATCH AGAINST 导致索引失效。

    • 失效示例

      -- 未使用全文索引
      SELECT * FROM articles WHERE content LIKE '%database%';  
      
    • 优化方法

      • 对文本搜索需求改用全文索引(FULLTEXT Index)。

      • 避免在全文索引列上混合使用 LIKE 和 MATCH

        SELECT * FROM articles WHERE MATCH(content) AGAINST('database');

    三、高级排查工具

    1. 开启慢查询日志

    -- 配置 my.cnf
    slow_query_log = 1
    slow_query_log_file = /var/log/mysql/slow.log
    long_query_time = 2   -- 记录执行超过2秒的SQL

    通过慢日志定位高频低效 SQL。

    2. 使用 OPTIMIZER_TRACE 分析优化器决策

    SET optimizer_trace = 'enabled=on';
    SELECT * FROM users WHERE age = 25;  -- 执行你的查询
    SELECT * FROM information_schema.optimizer_trace;  -- 查看优化器选择索引的过程

    3. 强制使用索引测试

    SELECT * FROM users FORCE INDEX (idx_age) WHERE age = 25;  -- 强制使用索引

    对比强制索引前后的执行时间,判断优化器是否选错索引。

    四、总结

    • 核心原则:索引失效的本质是 无法快速定位数据范围

    • 关键检查点

      • 避免对索引列进行计算或函数操作。

      • 确保查询条件符合最左前缀原则。

      • 注意隐式类型转换和通配符使用。

    • 工具辅助EXPLAIN、慢查询日志、OPTIMIZER_TRACE 是排查利器。

    http://www.xdnf.cn/news/667693.html

    相关文章:

  • 关于 Web 安全:6. 常见 CMS 开源系统风险点
  • 利用 `ngx_http_xslt_module` 实现 NGINX 的 XML → HTML 转换
  • 深度学习常用概念详解:从生活理解到技术原理
  • 新电脑配置五 jdk8,maven,idea,vscode
  • 单片机(MCU)的 IO 口静电、浪涌、电压异常等保护
  • OpenEuler-DNS多域服务器搭建
  • 基于 Node.js 的 Express 服务是什么?
  • div或button一些好看实用的 CSS 样式示例
  • Linux 下 C 语言实现工厂模式
  • 卓力达蚀刻工艺:精密制造的跨行业赋能者
  • day 33 python打卡
  • 【LeetCode 热题 100】打家劫舍 / 零钱兑换 / 单词拆分 / 乘积最大子数组 / 最长有效括号
  • DAY38打卡
  • Python打卡第38天
  • 零基础远程连接课题组Linux服务器,安装anaconda,配置python环境(换源),在服务器上运行python代码【2/3 适合小白,步骤详细!!!】
  • K8S Pod调度方法实例
  • 详解K8s API Server 如何处理请求的?
  • MySQL connection close 后, mysql server上的行为是什么
  • 【Elasticsearch】调用_flush api会调用_refresh 吗?
  • 火山引擎声音复刻
  • 安全生产例题
  • 知识图谱:AI时代语义认知的底层重构逻辑
  • 游戏引擎学习第314天:将精灵拆分成多个层
  • U 盘数据恢复全攻略
  • 说说 Kotlin 中的 Any 与 Java 中的 Object 有何异同?
  • Go 应用中的 Redis 连接与操作
  • NLua性能对比:C#注册函数 vs 纯Lua实现
  • Nginx--手写脚本压缩和切分日志(也适用于docker)
  • 【Linux】进程状态优先级
  • 【QT】在QT6中读取文件的方法