【MySQL12】进阶篇 | SQL优化

一、Insert 插入优化

1. 批量多行插入(优先推荐)

不要多次单条 insert,改成一条 SQL 批量写入,减少网络 IO 开销

sql

sql 复制代码
INSERT INTO tb_test VALUES(1, 'Tom'),(2, 'Cat'),(3, 'Jerry');

2. 优化小技巧

  1. 手动提交事务:多条插入包裹在事务内,减少事务提交次数
  2. 主键顺序插入:自增主键顺序写入性能远高于乱序主键

3. 超大批量数据:load data local infile

几十万、百万级数据,普通 insert 效率很低,使用本地文件高速导入

sql

sql 复制代码
-- 1.客户端启动时开启本地文件权限
mysql --local-infile -u root -p

-- 2.开启全局本地文件导入开关
SET GLOBAL local_infile = 1;

-- 3.查看参数是否开启成功
SELECT @@local_infile;

-- 4.加载本地文件导入数据表
LOAD DATA LOCAL INFILE '/root/sql1.log'
INTO TABLE tb_user
FIELDS TERMINATED BY ','
LINES TERMINATED BY '\n';

导入文件内数据主键有序可以规避页分裂,导入速度更佳。


二、主键优化(InnoDB 索引组织表 IOT)

InnoDB 属于索引组织表 (IOT),数据表物理行按照主键顺序存放。 因此主键设计直接影响页分裂、页合并,决定写入性能。

1. 页分裂

  • InnoDB 每页存储 2~N 行记录;行太大触发行溢出
  • 乱序主键插入 :随机 UUID、无序业务主键,新主键值需要插入到已有页中间,空间不足就会开辟新页,产生页分裂,消耗大量 IO。

2. 页合并

  1. 删除数据不会立刻物理删除,仅打上删除标记,空间可复用
  2. 参数 MERGE_THRESHOLD 默认阈值 50%
  3. 当页面空闲空间达到阈值,InnoDB 会尝试和相邻页面合并,优化存储空间。

3. 主键设计黄金原则

  1. 在业务允许前提下,主键字段长度尽量短
  2. 使用 AUTO_INCREMENT 自增主键,保证顺序插入,杜绝页分裂
  3. 禁止 UUID、身份证号等无序自然主键
  4. 业务代码尽量不要修改主键值

三、order by 排序优化

explain Extra 字段两种排序模式:

  1. Using filesort

没有有序索引;查询出符合条件的数据,放到 sort_buffer 排序缓冲区完成排序,性能较差。

  1. Using index(覆盖索引排序,最优)

依靠有序联合索引直接扫描返回有序结果,不需要额外排序。

实战演示

sql

sql 复制代码
-- 未建索引,Extra为 Using filesort
EXPLAIN SELECT id, age, phone FROM tb_user ORDER BY age;

-- 创建联合索引
CREATE INDEX idx_user_age_phone ON tb_user(age, phone);

-- 再次执行,命中 Using index
EXPLAIN SELECT id, age, phone FROM tb_user ORDER BY age;

多字段排序坑点:最左前缀法则

sql

sql 复制代码
-- 索引(age,phone),先按phone排序,违背最左前缀 → filesort
EXPLAIN SELECT id, age, phone FROM tb_user ORDER BY phone, age;

升降序混合排序

  • 索引字段排序方向要和 SQL order by 升降序匹配

sql

sql 复制代码
CREATE INDEX idx_user_age_pho_ad ON tb_user(age ASC, phone DESC);
EXPLAIN SELECT id, age, phone FROM tb_user ORDER BY age ASC, phone DESC;

order‑by 优化总结

  1. 排序字段建立联合索引,遵守最左前缀法则
  2. 优先使用覆盖索引,避免回表
  3. 多字段升降序不一致时,索引 ASC/DESC 需要对应排序规则
  4. 无法避免 filesort:调大排序缓冲区 sort_buffer_size

四、group by 分组优化

group by 本质也需要排序分组,同样依赖索引优化。

sql

sql 复制代码
-- 单字段分组
EXPLAIN SELECT profession, COUNT(*) FROM tb_user GROUP BY profession;

-- 多字段分组,索引顺序必须遵守最左前缀
EXPLAIN SELECT profession, age, COUNT(*) FROM tb_user GROUP BY profession, age;

优化要点:分组字段建立联合索引,多字段分组顺序匹配索引顺序,跳过额外排序操作。


五、limit 深分页优化

问题根源

limit offset,size,offset 数值越大,MySQL 需要扫描前面大量废弃数据,速度越慢

sql

sql 复制代码
-- 深度分页,性能极差
SELECT * FROM tb_sku LIMIT 9000000,10;

优化方案:覆盖索引 + 子查询关联

  1. 先通过索引快速查出目标页主键 id(覆盖索引无需回表,速度很快)
  2. 再根据主键关联查询整行数据

sql

sql 复制代码
SELECT s.*
FROM tb_sku s
INNER JOIN (
    SELECT id FROM tb_sku ORDER BY id LIMIT 9000000,10
) a ON s.id = a.id;

六、count 计数优化

四种 count 底层原理(InnoDB)

  1. count (主键 id):遍历整张表读取每一行主键,返回到服务层累加
  2. count (普通字段)
    • 字段无 not null:读取字段、判断 null 之后计数
    • 字段有 not null:直接读取字段值累加
  3. count(1):引擎遍历表,不需要读取字段,服务层填充 1 进行计数
  4. count(*):MySQL 专门做底层优化,不读取任何行字段,直接按行计数,性能天花板

性能排序

count(字段) < count(主键id) < count(1) < count(*)

开发规范:统计总行数固定使用 COUNT(*) 超大数据量表可以业务层维护计数器,实时缓存总数,避免频繁 count 扫描全表。


七、update 更新优化(行锁 & 表锁大坑)

InnoDB 的行锁是加在索引上,不是加在记录上;索引失效,行锁直接升级成全表表锁!

示例

sql

sql 复制代码
-- id为主键索引,命中索引 → 行锁,只锁住该行
UPDATE course SET name = 'javaEE' WHERE id = 1;

-- name无索引,索引失效 → 升级表锁,锁住整张表阻塞其他写入
UPDATE course SET name = 'SpringBoot' WHERE name = 'PHP';

-- 为更新条件字段建立索引
CREATE INDEX idx_course_name ON course(name);

-- 索引生效,走行锁
UPDATE course SET name = 'Spring' WHERE name = 'SpringBoot';

update 优化总结

  1. where 后面的更新条件字段一定要建立索引
  2. 避免索引失效:函数、隐式类型转换、模糊前缀通配符都会废掉索引,触发表锁

八、SQL 优化整体总结

  1. Insert :批量插入、事务手动提交、主键顺序写入;海量数据优先 load data local infile
  2. 主键优化:短主键、自增顺序主键,减少页分裂和页合并开销,禁用无序 UUID 主键
  3. order by 依靠有序索引实现 Using index,规避 Using filesort,遵守最左前缀、覆盖索引
  4. group‑by:分组字段建立联合索引
  5. limit 深分页:覆盖索引子查询先查主键再关联整表
  6. count :优先 count(*)
  7. update:更新条件带上有效索引,防止行锁升级表锁
  8. MySQL 绝大多数 SQL 优化本质 = 索引优化
相关推荐
IvorySQL1 小时前
PostgreSQL 日报|PG18.5 回归测试崩溃问题(8 月 12 日)
大数据·数据库·人工智能·postgresql
ltl1 小时前
学习型查询优化器:Neo、Bao、Balsa 与 LLM-CBO
数据库
ltl1 小时前
持久内存退场之后:ZNS SSD 与下一代非易失内存
数据库
故乡dee云4 小时前
AWS 产品太多不会选?按“网站、数据库、文件、日志”4 类需求快速匹配
数据库·云计算·aws
曹牧6 小时前
C#:问号
前端·数据库·c#
奇树谦6 小时前
《现代 Key-Value 数据库原理:从 B+Tree 到 LSM Tree》-第五篇:现代数据库横向对比
数据库·lsm-tree
李白客6 小时前
分布式集群与数据库产业:从单机到集群的架构跃迁与市场重构
数据库·分布式·架构
福大大架构师每日一题7 小时前
Redis 8.10.0 正式发布:紧凑哈希、批量导入、备份恢复、流与时序能力全面升级
数据库·redis·哈希算法
雨晨源码(同名B站)7 小时前
基于深度学习YoloV11农业病害虫害检测系统 智慧农业信息化综合管理平台 (附源码+lw文档+ppt)
数据库·人工智能·深度学习·yolo·信息可视化