MySQL 系统学习 第五阶段:企业级 MySQL 实战开发 第九章:数据库性能优化实战
一、为什么数据库会变慢很多初学者认为数据库慢就是 MySQL 性能不好。实际上大多数问题来自SQL 和表设计不合理。例如用户表user数据1000万条执行SELECT * FROM user WHERE usernameTom;数据库需要从第一条扫描到最后。这个过程叫全表扫描Full Table Scan二、什么是索引Index定义索引一种帮助数据库快速查询数据的数据结构。类似书的目录。没有索引看一本书逐页找第一页 第二页 第三页 ... 1000页有索引查目录直接定位第500页数据库没有索引逐行扫描有索引快速定位三、为什么索引能提高查询速度例如用户表100万数据。字段id username没有索引查询WHERE usernameTom流程第1行 ↓ 第2行 ↓ 第3行 ↓ ... 100万行复杂度O(n)有索引索引树 Tom ↓ 数据位置 ↓ 直接读取接近O(log n)四、MySQL索引结构BTree ⭐⭐⭐⭐⭐MySQL InnoDB 默认BTree。结构类似50 / \ 20 80 / \ / \ 10 30 60 90查询查90流程根节点 ↓ 80 ↓ 90不需要扫描所有数据。五、为什么不用二叉树普通二叉树问题数据量大高度太高。例如1000万数据二叉树可能几十层。BTree一个节点保存大量数据。高度低。优势查询快范围查询强适合磁盘读取六、索引类型1. 主键索引例如id BIGINT PRIMARY KEY自动创建。特点唯一。2. 普通索引例如用户搜索username创建CREATE INDEX idx_username ON user(username);3. 唯一索引例如邮箱email UNIQUE保证不能重复。4. 联合索引多个字段例如username status创建CREATE INDEX idx_user_status ON user(username,status);七、为什么企业需要联合索引场景后台用户列表条件WHERE usernameTom AND status1如果只有username索引。查询先找到Tom。再过滤status。联合索引(username,status)直接定位。效率更高。八、最左匹配原则 ⭐⭐⭐⭐⭐联合索引(username,status,age)有效WHERE usernameTom✅有效WHERE usernameTom AND status1✅有效WHERE usernameTom AND status1 AND age20✅无效WHERE status1❌无效WHERE age20❌原因索引顺序从左开始。九、什么情况下不要创建索引索引不是越多越好。1. 数据量小例如100条数据。全表扫描更快。2. 经常修改字段例如状态字段status如果频繁修改维护索引成本增加。3. 区分度低例如性别male female只有两个值。索引效果差。十、EXPLAIN 执行计划 ⭐⭐⭐⭐⭐优化SQL必须使用EXPLAIN例如EXPLAIN SELECT * FROM user WHERE usernameTom;查看数据库如何执行。重点字段type表示查询类型。最好const eq_ref ref较差ALL表示全表扫描。key实际使用索引。例如idx_username说明使用索引。rows扫描行数。越少越好。十一、慢 SQL 分析流程企业常用流程发现慢SQL ↓ EXPLAIN ↓ 查看是否走索引 ↓ 优化SQL ↓ 增加索引 ↓ 重新测试例如慢SELECT * FROM orders WHERE user_id100;检查没有索引typeALL优化添加INDEX(user_id)再次EXPLAINtyperef优化成功。十二、分页优化 ⭐⭐⭐⭐⭐普通分页LIMIT 100000,20问题MySQL先扫描100000条。然后丢弃。数据越大越慢。例如第500万页。优化方案1ID分页推荐SELECT * FROM user WHERE id500000 LIMIT 20;利用主键索引。速度快。优化方案2记录最后ID例如第一页返回lastId20第二页WHERE id20互联网大量使用。十三、大数据量查询优化1. 不查询无用字段不要SELECT *推荐SELECT id,name减少网络传输。2. 避免深层JOIN例如user join order join product join payment复杂。拆开查询。3. 热点数据缓存例如商品详情访问频繁。使用Redis。十四、TypeORM 性能优化1. 不滥用 relations错误find({ relations:{ orders:true, roles:true, permissions:true } })可能生成巨大JOIN。推荐按需查询。2. 使用 select不要find()全部字段。推荐find({ select:{ id:true, username:true } })3. 分页必须限制错误find()查询百万数据。正确find({ skip:0, take:20 })4. 批量操作错误循环for(){ save() }推荐批量save([ user1, user2, user3 ])十五、企业索引设计案例用户表user字段id username phone status create_time查询后台搜索WHERE username AND status索引INDEX(username,status)十六、订单表优化案例订单orders id user_id status create_time常见查询用户订单WHERE user_id100 ORDER BY create_time DESC索引INDEX( user_id, create_time )原因同时满足查询 排序。十七、数据库优化原则总结SQL层面✅ 不使用SELECT *✅ 避免全表扫描✅ 合理分页✅ 避免复杂JOIN表设计✅ 合理字段类型✅ 合理索引✅ 避免冗余数据TypeORM✅ 控制查询字段✅ 合理分页✅ 不滥用relations✅ 批量操作十八、本章总结表知识作用索引提高查询速度BTreeMySQL索引结构联合索引优化多条件查询最左匹配决定索引是否生效EXPLAIN分析SQL慢SQL定位性能问题ID分页解决深分页select减少数据量relations避免巨大JOIN本章一句话总结数据库性能优化的核心不是让数据库更快而是让数据库少做无用工作。