MySQL索引选择与失效场景全解析

 更新时间:2025年06月19日 09:42:01   作者:北辰alk  
在MySQL数据库中,索引是一种重要的优化手段,它能够显著提升查询速度,尤其是在大数据量的表中,然而,如果不正确地使用,索引可能会失去作用,导致查询性能下降,所以本文给大家介绍了MySQL索引选择与失效场景全解析,需要的朋友可以参考下

一、适合建立索引的字段特征

1.1 高选择性的字段

选择性公式

选择性 = 不重复的值数量(DISTINCT) / 总记录数

选择性越接近1,索引效果越好

示例分析

-- 查看字段选择性
SELECT 
  COUNT(DISTINCT gender)/COUNT(*) AS gender_selectivity,
  COUNT(DISTINCT phone)/COUNT(*) AS phone_selectivity
FROM users;

1.2 常用查询条件的字段

查询类型索引效果示例
WHERE条件★★★WHERE user_id = 1001
JOIN条件★★★ON a.order_id = b.id
排序字段★★ORDER BY create_time DESC
分组字段★★GROUP BY department

1.3 具体推荐场景

1.3.1 应当建索引的字段

  • 主键和外键字段(自动创建)
  • 高频查询的WHERE条件字段
  • 多表JOIN的关联字段
  • 排序和分组字段(特别是组合排序)
  • 区分度高的状态字段(如订单状态)

1.3.2 数值类型优先

-- 好的索引字段
ALTER TABLE products ADD INDEX idx_category_id (category_id);  -- 整型
ALTER TABLE users ADD INDEX idx_phone (phone);  -- 定长字符串

-- 较差的索引选择
ALTER TABLE logs ADD INDEX idx_content (content(255));  -- 长文本前缀索引

二、索引失效的8大常见场景

2.1 违反最左前缀原则

联合索引结构示例

ALTER TABLE orders ADD INDEX idx_user_status (user_id, status);

失效案例

-- 有效使用索引
EXPLAIN SELECT * FROM orders WHERE user_id = 1001 AND status = 1;

-- 部分失效(只用到了user_id)
EXPLAIN SELECT * FROM orders WHERE user_id = 1001;

-- 完全失效(跳过了user_id)
EXPLAIN SELECT * FROM orders WHERE status = 1;

2.2 对索引列使用函数或运算

失效示例

-- 索引失效
EXPLAIN SELECT * FROM users WHERE DATE(create_time) = '2023-01-01';
EXPLAIN SELECT * FROM products WHERE price + 100 > 500;

-- 优化方案
EXPLAIN SELECT * FROM users 
WHERE create_time BETWEEN '2023-01-01 00:00:00' AND '2023-01-01 23:59:59';

2.3 隐式类型转换

常见陷阱

-- phone字段是varchar类型
EXPLAIN SELECT * FROM users WHERE phone = 13800138000;  -- 失效
EXPLAIN SELECT * FROM users WHERE phone = '13800138000';  -- 有效

-- 枚举值比较
EXPLAIN SELECT * FROM orders WHERE status = '1';  -- 可能失效
EXPLAIN SELECT * FROM orders WHERE status = 1;    -- 有效

2.4 使用不等于(!=或<>)

失效分析

-- 索引失效
EXPLAIN SELECT * FROM users WHERE age != 30;

-- 优化方案(范围查询+union)
EXPLAIN SELECT * FROM users WHERE age < 30 
UNION ALL 
SELECT * FROM users WHERE age > 30;

2.5 LIKE以通配符开头

对比示例

-- 索引失效
EXPLAIN SELECT * FROM users WHERE name LIKE '%张%';

-- 索引有效(前缀匹配)
EXPLAIN SELECT * FROM users WHERE name LIKE '张%';

-- 特殊优化方案(全文索引)
ALTER TABLE users ADD FULLTEXT INDEX ft_idx_name (name);
EXPLAIN SELECT * FROM users WHERE MATCH(name) AGAINST('张*' IN BOOLEAN MODE);

2.6 OR条件使用不当

失效场景

-- 索引失效(其中一个条件无索引)
EXPLAIN SELECT * FROM users WHERE user_id = 1001 OR register_ip = '192.168.1.1';

-- 优化方案
EXPLAIN SELECT * FROM users WHERE user_id = 1001
UNION ALL
SELECT * FROM users WHERE register_ip = '192.168.1.1' AND user_id != 1001;

2.7 数据分布不均匀

案例演示

-- 当status=1占90%数据时
EXPLAIN SELECT * FROM orders WHERE status = 1;  -- 可能全表扫描

-- 查看数据分布
SELECT status, COUNT(*) FROM orders GROUP BY status;

2.8 索引列参与IS NULL判断

特殊情况

-- MySQL 5.7+可以走索引
EXPLAIN SELECT * FROM users WHERE phone IS NULL;

-- 通常需要结合其他条件
EXPLAIN SELECT * FROM users WHERE phone IS NULL AND create_time > '2023-01-01';

三、高级索引失效场景

3.1 索引合并导致的性能问题

-- 可能不如预期高效
EXPLAIN SELECT * FROM users 
WHERE username = 'admin' OR email = 'admin@example.com';

-- 优化方案
CREATE INDEX idx_username_email ON users(username, email);

3.2 范围查询后的索引失效

-- 只有user_id和status能用索引,age失效
EXPLAIN SELECT * FROM orders 
WHERE user_id = 1001 AND status > 0 AND age = 30;

-- 优化索引顺序
ALTER TABLE orders ADD INDEX idx_user_age_status (user_id, age, status);

3.3 不同字符集比较

-- 不同字符集比较导致失效
EXPLAIN SELECT * FROM users u JOIN logs l 
ON u.username = l.operator 
WHERE u.charset = 'utf8mb4' AND l.charset = 'latin1';

四、索引使用最佳实践

4.1 索引设计黄金法则

三星索引原则

  • 一星:WHERE条件列是索引前缀
  • 二星:ORDER BY/GROUP BY列在索引中
  • 三星:SELECT列被索引覆盖

索引维护成本

  • 写操作需要更新索引
  • 每个表最佳索引数通常为3-5个

4.2 实战案例解析

电商系统优化

-- 原始查询
SELECT product_id, product_name, price 
FROM products 
WHERE category_id = 5 
AND status = 1 
AND stock > 0 
ORDER BY sales_volume DESC 
LIMIT 20;

-- 优化方案
ALTER TABLE products ADD INDEX idx_cat_status_stock_sales 
(category_id, status, stock, sales_volume DESC);

4.3 监控与调优工具

索引使用分析

-- 查看未使用的索引
SELECT * FROM sys.schema_unused_indexes;

-- 索引统计信息
SHOW INDEX FROM products;

-- 查询性能分析
EXPLAIN ANALYZE SELECT * FROM orders WHERE user_id = 1001;

五、MySQL 8.0索引新特性

5.1 倒序索引

ALTER TABLE orders ADD INDEX idx_create_time (create_time DESC);

5.2 隐藏索引

-- 测试删除索引的影响
ALTER TABLE users ALTER INDEX idx_email INVISIBLE;
ALTER TABLE users ALTER INDEX idx_email VISIBLE;

5.3 函数索引

-- 对JSON字段建立索引
ALTER TABLE products ADD INDEX idx_price_data ((CAST(price_data->'$.price' AS DECIMAL(10,2))));

六、总结与决策流程图

6.1 索引创建决策流程

6.2 索引失效排查清单

  • 检查EXPLAIN执行计划
  • 验证SQL是否遵循最左前缀原则
  • 检查是否有隐式类型转换
  • 排查是否使用了函数或运算
  • 分析数据分布情况
  • 确认字符集和排序规则一致性

通过系统性地理解索引适用场景和失效原理,可以显著提升数据库查询性能。实际应用中应当结合业务特点和数据分布,定期审查索引效果,避免过度索引和索引滥用。

以上就是MySQL索引选择与失效场景全解析的详细内容,更多关于MySQL索引选择与失效的资料请关注脚本之家其它相关文章!

相关文章

  • Navicat Premium操作MySQL数据库(执行sql语句)

    Navicat Premium操作MySQL数据库(执行sql语句)

    这篇文章主要介绍了Navicat Premium操作MySQL数据库(执行sql语句),文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-11-11
  • MySQL中获取时间的所有方法小结

    MySQL中获取时间的所有方法小结

    在MySQL数据库开发中,获取时间是一个常见的需求,MySQL提供了多种方法来获取当前日期、时间和时间戳,并且可以对时间进行格式化、计算和转换,本文介绍了一些常用的MySQL时间函数及其示例,需要的朋友可以参考下
    2024-07-07
  • MySQL Replace INTO的使用

    MySQL Replace INTO的使用

    今天DST里面有个插件作者问我关于Replace INTO和INSERT INTO的区别,我和他说晚上上我的blog看吧,那时候还在忙,现在从MYSQL手册里找了点东西,MYSQL手册里说REPLACE INTO说的还是比较详细的.
    2008-04-04
  • MySQL数据库服务器端核心参数详解和推荐配置

    MySQL数据库服务器端核心参数详解和推荐配置

    MySQL手册上也有服务器端参数的解释,以及参数值的相关说明信息,现针对我们大家重点需要注意、需要修改或影响性能 的服务器端参数,作其用处的解释和如何配置参数值的推荐,此事情拖了不少时间,为方便大家帮忙纠错
    2011-12-12
  • 服务从mysql迁移达梦数据库的实现方案

    服务从mysql迁移达梦数据库的实现方案

    达梦数据库(DM8)作为主流国产关系型数据库,兼容MySQL协议和大部分语法,这篇文章主要介绍了服务从mysql迁移达梦数据库的实现方案,文中通过代码介绍的非常详细,需要的朋友可以参考下
    2026-05-05
  • Mysql添加、删除、主键(外键)方法详细讲解

    Mysql添加、删除、主键(外键)方法详细讲解

    MySQL是一种广泛使用的开源关系型数据库管理系统,在数据库设计中主键和外键是两个重要的概念,下面这篇文章主要给大家介绍了关于Mysql添加、删除、主键(外键)方法的相关资料,需要的朋友可以参考下
    2024-06-06
  • MySQL DNS的使用过程详细分析

    MySQL DNS的使用过程详细分析

    当 mysql 客户端连接 mysql 服务器 (进程为:mysqld),mysqld 会创建一个新的线程来处理该请求。该线程先检查是否主机名在主机名缓存中
    2012-11-11
  • mysql巡检脚本(必看篇)

    mysql巡检脚本(必看篇)

    下面小编就为大家带来一篇mysql巡检脚本(必看篇)。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2017-03-03
  • 解决Navicat远程连接MySQL出现 10060 unknow error的方法

    解决Navicat远程连接MySQL出现 10060 unknow error的方法

    这篇文章主要介绍了解决Navicat远程连接MySQL出现 10060 unknow error的方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2019-12-12
  • MySQL 安装配置超完整教程

    MySQL 安装配置超完整教程

    MySQL 是一款广泛使用的开源关系型数据库管理系统(RDBMS),由瑞典 MySQL AB公司开发,目前属于Oracle公司旗下产品,这篇文章主要介绍了MySQL安装配置超完整教程,需要的朋友可以参考下
    2025-05-05

最新评论