一张5000万行的表,加索引从45秒到0.02秒——索引设计你真的会吗

我是小耶,干运营半路出家的野生DBA------写功课只是为了我踩过的坑,你们别再踩了!

今天不搞虚的,直接上实验:一张 5000 万行的订单表,对比无索引和有索引的查询性能。

实验环境 ​:MySQL 8.0,innodb_buffer_pool_size 默认配置,订单表结构含 user_idorder_dateamount 等字段。

1. 无索引查询

ini 复制代码
SELECT * FROM orders WHERE user_id = 123456;

耗时 ​45 秒​。CPU 飙升,应用超时。

2. 添加单列索引

sql 复制代码
ALTER TABLE orders ADD INDEX idx_user_id (user_id);

再次执行相同查询:​0.02 秒 ​。性能提升 ​2250 倍​。

原因​:InnoDB 默认使用 B+ 树索引。没有索引时,执行全表扫描,逐行读取 5000 万条数据;有索引后,通过 B+ 树进行二分查找,树高通常为 3~4 层,每次查询只需 3~4 次磁盘 I/O,所以速度极快。


什么情况下应该建索引?

  • WHERE 条件中频繁出现的列
  • JOIN 的关联列
  • ORDER BYGROUP BY 的列

什么情况下不应建索引?

  • 列的区分度极低(例如 gender 只有男/女)。索引无法有效过滤数据,反而增加维护成本。
  • 频繁更新的列(UPDATE 会同时更新索引,写性能下降)。
  • 很少作为查询条件的列(索引占空间但无收益)。

进阶1:联合索引与最左前缀原则

如果经常同时按 user_idorder_date 查询,可以建联合索引:

sql 复制代码
ALTER TABLE orders ADD INDEX idx_user_date (user_id, order_date);

联合索引的 B+ 树先按第一列排序,再按第二列排序。​查询条件必须从索引最左侧开始连续匹配​,才能使用索引。

  • WHERE user_id = 123 ------ 可用
  • WHERE user_id = 123 AND order_date > '2026-01-01' ------ 可用
  • WHERE order_date > '2026-01-01' ------ 无法使用,因为第一列缺失
  • WHERE user_id = 123 AND amount > 100 ------ 只能用到 user_id 部分,amount 在索引中不连续

如何确定联合索引的列顺序?

  • 等值查询的列放前面范围查询的列放后面
  • 例如 WHERE user_id = 123 AND order_date > '2026-01-01',索引 (user_id, order_date) 最优。
  • 如果有多个等值条件,把区分度高的列放左边。

进阶2:覆盖索引

如果 SELECT 的列全部包含在索引中,InnoDB 可以直接从索引返回数据,​无需回表​,性能进一步提升。

ini 复制代码
CREATE INDEX idx_user_date_amount ON orders (user_id, order_date, amount);
SELECT user_id, order_date, amount FROM orders WHERE user_id = 123;

执行 EXPLAIN 会在 Extra 列显示 Using index。覆盖索引能减少大量 I/O,尤其适合统计类查询。


常见错误:隐式类型转换导致索引失效

如果索引列是字符串类型,但查询时传入数字,MySQL 会对列做隐式转换,导致索引失效。

sql 复制代码
-- phone 是 varchar,正确做法是加引号
SELECT * FROM users WHERE phone = '13800000000';  -- 走索引
SELECT * FROM users WHERE phone = 13800000000;    -- 不走索引

小结

索引是数据库性能优化的核心手段,但不是越多越好。建议:

  1. 对高频查询的 WHEREJOINORDER BY 列建索引。
  2. 联合索引遵循最左前缀原则,范围查询列放最后。
  3. 尽量使用覆盖索引避免回表。
  4. 注意隐式类型转换、函数操作对索引的影响。

你可以花 10 分钟检查下业务核心表的慢查询日志,看看哪些查询缺少合适的索引。往往一两处优化就能让整个系统性能翻倍。

小耶在手,SQL 不愁。

你遇到过"建了索引还是慢"的情况吗?发出来我帮你分析分析~

相关推荐
SamDeepThinking4 小时前
程序员如何接受工作内容毫无意义?
java·后端·程序员
AI绘画哇哒哒5 小时前
RAG 系统中文档切分策略:如何选择合适的 chunk size?| 收藏这份实用指南,小白也能轻松上手大模型学习
人工智能·学习·ai·程序员·大模型·产品经理·转行
python零基础入门小白5 小时前
从0到1:手把手教你用Coze打造AI Agent,小白也能转行AI!
人工智能·学习·程序员·大模型·agent·产品经理·ai大模型
阿里嘎多学长8 小时前
2026-05-04 GitHub 热点项目精选
开发语言·程序员·github·代码托管
唐叔在学习8 小时前
TodoList:我的待办助手
python·程序员·ai编程·待办应用
程序员鱼皮9 小时前
试了下 Codex 新出的宠物功能,吊打 Claude Code,给我玩上头了。。
ai·程序员·编程·ai编程·codex
SimonKing9 小时前
OpenCode 在 IDEA 中使用 ACP 协议 VS 直接使用 TUI,哪个编程方式更是你的菜?
java·后端·程序员
AIGC安琪10 小时前
Transformer 和 LLM 到底是什么关系?
人工智能·深度学习·ai·语言模型·程序员·大模型·transformer
阿里嘎多学长10 小时前
2026-05-02 GitHub 热点项目精选
开发语言·程序员·github·代码托管