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索引选择与失效的资料请关注脚本之家其它相关文章!

相关文章

  • MySQL分区之HASH分区详解

    MySQL分区之HASH分区详解

    hash分区的目的是将数据按照某列进行hash计算后更加均匀的分散到各个分区,下面这篇文章主要给大家介绍了关于MySQL分区之HASH分区的相关资料,文中通过示例代码介绍的非常详细,需要的朋友可以参考下
    2022-04-04
  • mysql5.7中的密码忘记如何找回

    mysql5.7中的密码忘记如何找回

    这篇文章主要介绍了mysql5.7中的密码忘记如何找回问题,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2023-06-06
  • MySQL中describe命令的使用方法小结

    MySQL中describe命令的使用方法小结

    这篇文章主要介绍了MySQL中describe命令的使用方法小结,describe命令主要用于获取表或列等的各种信息,需要的朋友可以参考下
    2015-12-12
  • 详解MySQL子查询(嵌套查询)、联结表、组合查询

    详解MySQL子查询(嵌套查询)、联结表、组合查询

    这篇文章主要介绍了MySQL子查询(嵌套查询)、联结表、组合查询,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2019-03-03
  • linux版mysql8配置表名不区分大小写问题

    linux版mysql8配置表名不区分大小写问题

    文章介绍了MySQL 8的安装步骤,包括配置忽略大小写、备份数据、停止和删除数据库文件、配置my.cnf文件、初始化、启动服务和登录设置密码,还讨论了在配置远程连接时遇到的常见问题,特别是MySQL 8版本中由于密码加密方法变化导致的问题解决方法
    2024-11-11
  • mysql主键的缺少导致备库hang住

    mysql主键的缺少导致备库hang住

    最近线上频繁的出现slave延时的情况,经排查发现为用户在删除数据的时候,由于表主键的主键的缺少,同时删除条件没有索引,或或者删除的条件过滤性极差,导致slave出现hang住
    2016-05-05
  • Mysql5.7修改root密码教程

    Mysql5.7修改root密码教程

    今天小编就为大家分享一篇关于Mysql5.7修改root密码教程,小编觉得内容挺不错的,现在分享给大家,具有很好的参考价值,需要的朋友一起跟随小编来看看吧
    2019-02-02
  • MySQL该如何判断不为空详析

    MySQL该如何判断不为空详析

    在MySQL数据库中,在不同的情形下,空值往往代表不同的含义,这是MySQL数据库的一种特性,下面这篇文章主要给大家介绍了关于MySQL该如何判断不为空的相关资料,需要的朋友可以参考下
    2023-02-02
  • 基于mysql乐观锁实现秒杀的示例代码

    基于mysql乐观锁实现秒杀的示例代码

    本文主要介绍了基于mysql乐观锁实现秒杀,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2022-07-07
  • MySQL出现SQL Error (2013)连接错误的解决方法

    MySQL出现SQL Error (2013)连接错误的解决方法

    这篇文章主要介绍了MySQL出现SQL Error (2013)连接错误的解决方法,2013错误主要还是在于用户的授权问题,需要的朋友可以参考下
    2016-06-06

最新评论