MySQL索引使用技巧:让你的数据库查询速度飞起来

352 阅读5分钟

image.png

一、先讲个真实故事:一次索引优化的威力

上周帮朋友公司排查一个生产问题:用户注册接口响应时间从200ms暴涨到8秒。查看慢查询日志,发现一条简单的SELECT * FROM users WHERE phone='138xxxx'竟然执行了6.8秒!

问题根源:2000万用户表,phone字段没有索引,每次查询都在做全表扫描。

解决方案:给phone字段加索引后,查询时间直接降到0.002秒,性能提升3400倍!

这就是索引的魔法。接下来带你解锁MySQL索引的正确使用姿势。

二、索引原理大白话(新手必看)

1. 索引就像字典的目录

没有索引时找数据:
SELECT * FROM book WHERE content='abc' ➔ 需要逐页翻完整本书

加了索引后:
直接查目录找到页码 ➔ 精准定位内容

2. 底层数据结构

  • B+树:MySQL最常用的索引结构(平衡多路查找树)
  • 哈希索引:Memory引擎专用,适合等值查询
  • 全文索引:用于文本搜索(倒排索引)

B+树索引结构示意图(文字描述版)

          [根节点]
        /     |     \
 [非叶节点A] [非叶节点B] [非叶节点C]
   /  |  \     /  |  \     /  |  \
[叶子节点1]->[叶子节点2]->[叶子节点3]->...(双向链表连接)

关键特征标注建议:

  1. 树形结构:3层结构(根节点-非叶节点-叶子节点)

  2. 节点内容

    • 非叶节点:存储键值 + 子节点指针(如[15][→] [30][→] [45][→]
    • 叶子节点:存储完整数据/主键 + 前后指针(双向链表)
  3. 数据连续性:用箭头表示叶子节点之间的链表连接

  4. 平衡特性:所有叶子节点在同一层


三、必须掌握的6大核心技巧

1. 最左匹配原则(联合索引的精髓)

创建联合索引:

ALTER TABLE orders ADD INDEX idx_status_created(status, created_at);

生效场景:

  • WHERE status=1 ➔ ✅
  • WHERE status=1 AND created_at>'2023-01-01' ➔ ✅
  • WHERE created_at>'2023-01-01' ➔ ❌ (跳过了最左字段)

2. 避免索引失效的坑

-- 案例:2000万用户表查询
SELECT * FROM users 
WHERE YEAR(create_time) = 2023; -- ❌ 函数导致索引失效

-- 正确写法
SELECT * FROM users 
WHERE create_time BETWEEN '2023-01-01' AND '2023-12-31'; -- ✅

其他失效场景:

  • 使用!=NOT IN
  • 类型转换(如字符串字段用数字查询)
  • LIKE以通配符开头'%abc'

3. 覆盖索引的妙用

-- 普通查询(需要回表)
SELECT * FROM products WHERE category='手机';

-- 覆盖索引优化
ALTER TABLE products ADD INDEX idx_category_name(category, name);
SELECT category, name FROM products WHERE category='手机'; -- ✅ 直接走索引

4. 巧用前缀索引

当索引长文本字段时:

-- 完整索引(占用空间大)
ALTER TABLE articles ADD INDEX idx_content(content);

-- 优化:取前20字符
ALTER TABLE articles ADD INDEX idx_content(content(20));

5. 索引下推(Index Condition Pushdown,ICP)

MySQL 5.6+的黑科技:

SELECT * FROM users 
WHERE age > 18 
AND name LIKE '张%';

-- 没有ICP:先通过age>18筛选,再回表查name
-- 有ICP:在存储引擎层直接过滤age和name

6. 唯一索引的取舍

优点:

  • 保证数据唯一性
  • 查询性能稍优于普通索引

代价:

  • 插入时需要唯一性校验
  • 影响写入性能(高并发场景)

四、真实场景案例库

案例1:电商订单查询优化

-- 原始SQL(执行时间2.3秒)
SELECT * FROM orders 
WHERE user_id=123 
AND status=3 
ORDER BY create_time DESC 
LIMIT 10;

-- 优化方案:创建联合索引
ALTER TABLE orders ADD INDEX idx_user_status_time(user_id, status, create_time);
-- 执行时间降为0.015秒

案例2:千万级用户表分页

-- 错误写法(越往后越慢)
SELECT * FROM users 
ORDER BY id 
LIMIT 1000000, 10;

-- 优化方案:游标分页
SELECT * FROM users 
WHERE id > 1000000 
ORDER BY id 
LIMIT 10;

五、这些坑千万别踩!

  1. 乱建索引综合症

    • 每个字段都加索引 ➔ 索引占用空间超过数据本身
    • 更新变慢:每次INSERT/UPDATE都要维护多个索引
  2. 过度依赖执行计划
    EXPLAIN不是万能药,要注意:

    • 数据量变化后执行计划可能改变
    • 索引统计信息不及时(可用ANALYZE TABLE刷新)
  3. 忽视隐式类型转换

-- phone是varchar类型
SELECT * FROM users WHERE phone=13800138000; -- ❌ 触发类型转换

六、性能监控三板斧

  1. 慢查询日志分析
-- 开启慢日志
SET GLOBAL slow_query_log = ON;
SET GLOBAL long_query_time = 1; -- 超过1秒的查询
  1. 查看索引使用情况
SHOW INDEX FROM table_name;
-- 关注Cardinality(基数),越接近行数越好
  1. 性能分析神器
EXPLAIN SELECT ...;
-- 重点关注:
-- type(最好到const/ref)
-- rows(扫描行数)
-- Extra(Using index/Using filesort)

七、终极使用原则

  1. 黄金平衡点
    索引数量 = 写入性能 vs 查询性能的平衡点

  2. 定期体检制度

    • 每月分析慢查询日志
    • 清理无用索引(推荐使用pt-index-usage工具)
  3. 不要盲目相信经验
    用数据说话:

    • 测试环境压测
    • 生产环境A/B测试

结语

索引就像数据库的加速器,但使用不当就会变成性能杀手。记住:最好的索引策略是根据业务场景量身定制。现在就去检查你的数据库,把学到的技巧用起来吧!

思考题:你在工作中遇到过哪些有意思的索引优化案例?欢迎在评论区分享你的实战经验!