一张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 不愁。

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

相关推荐
沉默王二3 小时前
你说你用Claude,你用的是 CLI,还是 Agent、Opus?
人工智能·程序员·claude
SimonKing4 小时前
别再把业务逻辑写进回调接口了!支付回调的正确打开方式
java·后端·程序员
梵得儿SHI1 天前
Vue 项目实战与性能优化:工程化与协作全指南(规范 + 配置 + 协作 + 文档)
前端·vue.js·代码规范·eslint·团队协作·前端工程化·前端架构
Gavin-Wang1 天前
swift 代码规范
蓝桥杯·swift·代码规范
BugShare1 天前
厌倦了使用 lsof 命令排查端口,来试试 sonar
运维·程序员
CadeCode1 天前
Vue3 代码风格推荐
前端·vue.js·代码规范
CadeCode1 天前
SpringBoot 代码风格推荐
java·spring boot·代码规范
SimonKing1 天前
通义灵码不仅改名,还要收费了!!!
java·后端·程序员
陈随易1 天前
Redis数据结构速通
前端·后端·程序员