当前位置: 首页 > news >正文

MySQL 极致性能优化指南——从 INSERT 到 UPDATE 的七大战场

MySQL 极致性能优化指南

——从 INSERT 到 UPDATE 的七大战场

适用版本:MySQL 8.0+
引擎:InnoDB(默认)
目标:同等硬件,并发翻倍,延迟减半


目录

  1. 插入数据优化
  2. 主键优化
  3. ORDER BY 优化
  4. GROUP BY 优化
  5. LIMIT 优化
  6. COUNT 优化
  7. UPDATE 优化(避免行锁升级)

1. 插入数据优化

  • InnoDB 每次插入都隐式开启事务,自动提交 = 每条一次 log flush → 磁盘 IO 暴涨
  • 顺序主键可减少页分裂
  • 大批量场景 LOAD DATAINSERT 快 10~20 倍

代码示例

-- 1. 单条→批量(10 倍提升)
INSERT INTO tb_user VALUES (1,'Tom'),(2,'Cat'),(3,'Jerry');  -- 合 1 条 SQL-- 2. 手动事务包裹(减少 log flush 次数)
START TRANSACTION;
INSERT INTO tb_user VALUES (1,'Tom'),(2,'Cat');
INSERT INTO tb_user VALUES (3,'Jerry'),(4,'Mary');
COMMIT;-- 3. 百万级导入 LOAD DATA(17 s 导入 100 W)
mysql --local-infile -u root -p
SET GLOBAL local_infile = 1;
LOAD DATA LOCAL INFILE '/tmp/user_100w.csv'
INTO TABLE tb_user
FIELDS TERMINATED BY ','
LINES TERMINATED BY '\n';

案例

某日志表 500 W 行/天,从 Spring Batch 单条 insert 改为 LOAD DATA 后,导入耗时由 45 min → 2 min 30 s


2. 主键优化

笔记

  • InnoDB 聚簇索引 → 数据行即叶子节点
  • 乱序插入触发 页分裂(移动 50 % 数据)
  • 过长主键使二级索引翻倍膨胀

代码示例

-- ✔ 推荐:短、自增、业务无关
CREATE TABLE good_pk (id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,username VARCHAR(50) NOT NULL UNIQUE
) ENGINE=InnoDB;-- ✘ 反面:UUID 字符串,长且乱序
CREATE TABLE bad_pk (id CHAR(36) PRIMARY KEY,   -- 36 字节,二级索引也跟着 36 字节username VARCHAR(50)
) ENGINE=InnoDB;

案例

订单表主键从 UUID 改为 雪花 ID(有序 Long),主键长度 36 → 8 字节,索引文件缩小 55 %,QPS 提升 30 %


3. ORDER BY 优化

笔记

  • 利用 索引有序性 消除额外排序(Using filesort
  • 联合索引 升降序 必须与 SQL 一致
  • 覆盖索引可彻底不回表

代码示例

-- 联合索引与排序方向一致
CREATE INDEX idx_age_phone ON tb_user(age ASC, phone DESC);-- 走索引,无 filesort
EXPLAIN SELECT age, phone
FROM tb_user
ORDER BY age ASC, phone DESC;
-- Extra: Using index

案例

分页查询 ORDER BY create_time DESC LIMIT 100000,10 原耗时 3.2 s;
增加 (create_time, id) 联合索引后 0.03 s,Extra 由 Using filesortUsing index


4. GROUP BY 优化

笔记

  • 语义:先排序后分组 → 索引有序可省排序
  • 分组列 + 查询列 = 覆盖索引,可 索引一把梭

代码示例

-- 索引顺序与 GROUP BY 一致
CREATE INDEX idx_dept_sal ON emp(dept_id, salary);-- 无临时表、无 filesort
SELECT dept_id, COUNT(*) cnt, MAX(salary) max_sal
FROM emp
GROUP BY dept_id;

案例

报表 SQL 按 dept_id 分组,原 临时表 + filesort 2.1 s;
加联合索引后 0.05 s,Extra 变为 Using index


5. LIMIT 优化

笔记

  • LIMIT offset, N 越往后越慢(全表扫描 offset 行)
  • 延迟关联 / 游标分页 把“跳行”改为“过滤主键”

代码示例

-- 传统深分页(慢)
SELECT * FROM orders ORDER BY id LIMIT 1000000, 20;-- 延迟关联(快)
SELECT o.*
FROM orders o
JOIN (SELECT id FROM orders ORDER BY id LIMIT 1000000, 20) t
ON o.id = t.id;

案例

管理后台翻页到 100 W 行,延迟关联 从 4.5 s → 0.08 s


6. COUNT 优化

笔记

  • COUNT(*)遍历最小二级索引(非聚簇)
  • MyISAM 维护行计数器,但不支持事务
  • 业务大屏可用 缓存 / 近似值 / 汇总表

代码示例

-- 最小索引扫描
SELECT COUNT(*) FROM user;  -- 自动选 idx_status 而非聚簇索引-- 汇总表(秒级)
CREATE TABLE user_count (cnt BIGINT UNSIGNED);
-- 定时刷新
REPLACE INTO user_count SELECT COUNT(*) FROM user;
-- 查询count
SELECT cnt FROM user_cnt_summary LIMIT 1;   -- < 10 ms

案例

1.2 亿行用户表 COUNT(*) 12 s;
增加 每日汇总表 后接口 < 10 ms


7. UPDATE 优化(避免行锁升级)

笔记

  • 无索引列更新 → 全表扫描 + 表锁(行锁升级)
  • 尽量 按主键/索引列 精确过滤
  • 批量更新拆小事务,锁持有时间 < 200 ms

代码示例

-- 反面:无索引,锁全表
UPDATE orders SET status=1 WHERE create_time < '2025-01-01';-- 正面:先加索引,再按主键范围更新
ALTER TABLE orders ADD INDEX idx_ctime_id(create_time, id);-- 分批更新,防锁等待
UPDATE orders
SET status=1
WHERE id BETWEEN 1 AND 100000AND create_time < '2025-01-01';
-- 循环 + 睡眠 100 ms,直至结束

案例

凌晨批量更新 300 W 行,原 单条 SQL 锁表 90 s 导致业务超时;
改为 索引 + 每批 1 W 行 后,锁等待降为 0,耗时 3 min 平滑结束。


8. 一键检查清单(上线前对照)

场景检查 SQL目标
插入EXPLAIN INSERT ...无自动提交、主键顺序
主键SHOW INDEX / SELECT COUNT(DISTINCT pk)短、有序、非业务
排序EXPLAIN ... ORDER BYExtra ≠ Using filesort
分组EXPLAIN ... GROUP BYExtra ≠ Using temporary
分页EXPLAIN ... LIMIT offset, N走索引 + 延迟关联
计数SHOW TABLE STATUS / 汇总表< 100 ms
更新EXPLAIN UPDATE ... WHERE用索引、分批

9. 结论

MySQL 优化是“索引 + 算法 + 习惯”的组合拳:

  • :顺序主键、批量提交、LOAD DATA
  • :覆盖索引、最左前缀、延迟关联
  • :精准过滤、小事务、分批

把本文 SQL 全部 EXPLAIN 一遍,让 Extra 里只剩 Using index,你就拥有了生产级的高可用 MySQL。


文章转载自:

http://bMK5NYTY.fnfxp.cn
http://bBztwEYp.fnfxp.cn
http://OzCJVkWF.fnfxp.cn
http://l9S6rcWW.fnfxp.cn
http://Ay2YKIO1.fnfxp.cn
http://Owa0ctew.fnfxp.cn
http://OkUIsyKc.fnfxp.cn
http://vShe1skQ.fnfxp.cn
http://5fu0tlwZ.fnfxp.cn
http://ulFdCUGg.fnfxp.cn
http://WKCcmEAJ.fnfxp.cn
http://RxuLSlDk.fnfxp.cn
http://RrpSfVdq.fnfxp.cn
http://RDVG5dEu.fnfxp.cn
http://n7m52eP5.fnfxp.cn
http://UYYsyY9x.fnfxp.cn
http://hlQek7jx.fnfxp.cn
http://T0Ez5ohP.fnfxp.cn
http://kSzB3olW.fnfxp.cn
http://xOub9oV3.fnfxp.cn
http://whSl1FDp.fnfxp.cn
http://4WKDbLQ6.fnfxp.cn
http://GTmEzSEs.fnfxp.cn
http://Xr1SabKk.fnfxp.cn
http://AvNZhjAl.fnfxp.cn
http://wCea7Zxp.fnfxp.cn
http://hwR2ytXy.fnfxp.cn
http://EsIFqIbk.fnfxp.cn
http://20zMrYHC.fnfxp.cn
http://ZfY6AeUY.fnfxp.cn
http://www.dtcms.com/a/384642.html

相关文章:

  • Web前端开发工具有哪些?常用Web前端开发工具推荐、Web前端开发工具对比
  • 一款开源的im简介
  • Vite Plugin PWA – 零配置构建现代渐进式Web应用
  • 用爬虫技术获取淘宝商品评论——提升购物体验的利器
  • 【新手指南】async/await与Axios的用法
  • Java的并发编程1
  • 使用prometheus operator监控部署在k8s集群外的mysql实例
  • Notepad++ 8.7 64位安装教程(附安装包)​
  • 《大数据之路1》笔记3:数据管理
  • 【代码随想录day 27】 力扣 376. 摆动序列
  • 使用conda导出虚拟环境
  • LeetCode热题100--105. 从前序与中序遍历序列构造二叉树--中等
  • 计算机网络---数据链路层上
  • 《FastAPI零基础入门与进阶实战》第18篇:Token验证改善--CRUD中应用
  • QT(4)
  • DevOps历程--Drone安装使用详细教程
  • 微信小程序选择图片、视频、音频
  • 【C++上岸】C++常见面试题目--网络篇(第二十三期)
  • mapbox进阶,使用jsts实现平角缓冲区
  • A股大盘数据-20250915分析
  • MySQL服务启动全平台指南:从Windows服务、Linux systemctl到macOS的完整攻略
  • 八、vue3后台项目系列——封装layout页面下切换组件Appmain
  • 学习React-12-useEffect
  • MFC_Button
  • [K8S学习笔记]YAML相关
  • 贪心算法在物联网能耗优化中的应用
  • 使用paddlepaddle-Gpu库时的一个小bug!
  • 从 Linux 到 Kubernetes:操作系统的演变与云原生未来
  • Java网络编程:(socket API编程:TCP协议的 socket API -- 服务器端处理请求的三个步骤)
  • 新能源汽车总装车间案例:四台S7-1200通过无线网桥同步控制16组ET 200SP的秘诀