实战SQL优化(以MySQL深分页为例)
1 准备表结构
CREATE TABLE `student` (
`id` int NOT NULL AUTO_INCREMENT,
`user_no` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL,
`user_name` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL,
`score` decimal(10, 2) NULL DEFAULT NULL,
`create_time` datetime NULL DEFAULT NULL,
`update_time` datetime NULL DEFAULT NULL,
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic;
2 需求
按照成绩降序排列,并查询字段 user_no,user_name,score,做一个带排序的分页查询
3 自动执行数据
delimiter $$
CREATE PROCEDURE BatchInsert ( IN initId INT, IN loop_counts INT)BEGIN
DECLARE Var INT;
DECLARE ID INT;
SET Var = 0;
SET ID = initId;
SET autocommit = 0;
WHILE Var < loop_counts DO
INSERT INTO `test`.`student` ( `user_no`, `user_name`, `score`, `create_time`, `update_time` )
VALUES
(
CONCAT( '学号', ID ),
CONCAT( '姓名', ID ),
FLOOR( 1 + RAND()* 100 ),
DATE_ADD( '2023-3-30 16:08:00', INTERVAL ROUND( RAND()* 1000+1 ) DAY ),
DATE_ADD( '2023-3-30 16:08:00', INTERVAL ROUND( RAND()* 1000+1 ) DAY )
);
SET ID = ID + 1;
SET Var = Var + 1;
END WHILE;
COMMIT;
END $$;
delimiter;
CALL BatchInsert(1,2000000)
4 需要分页的sql
SELECT user_no,user_name,score FROM student ORDER BY score DESC LIMIT 5,20 #浅分页
SELECT user_no,user_name,score FROM student ORDER BY score DESC LIMIT 80000,20 #深分页
5 分页执行计划
通过执行计划 expladin 看下执行效率:
浅分页:

深分页:

可以看出 type=all 都是走的全表扫描,并且都使用了额外的文件排序,现在记录一下执行时间:
浅分页:0.887s,深分页:1.427s
5.1 对排序字段添加索引
对 score 添加索引:alter table student add index idx_score(score)
浅分页:
耗时:0.021s
深分页:
耗时:1.475s
可以看出,虽然对排序字段加了索引,但是由于深分页偏移量太大,还是选择了走全表扫描 type=all。并额外使用了文件排序。
可以分析出,排序需要成本,回表也需要成本,浅分页由于偏移量小,回表成本低,所以执行效率有很大的提升,深分页偏移量大,回表成本太高了,所以需要降低深分页回表的成本。
5.2 建立联合索引
建立联合索引,就是为了消除回表带来的效率损耗。
alter table student add index idx_no_name_score(score,user_no,user_name)
浅分页:

耗时:0.024s
深分页:

耗时:0.047s
可以看到,使用联合索引已经可以解决了回表的问题,两者的执行效率也高了很多,但是这种做法有一个缺点,如果我们要查询出来的数据多了一个字段,就得重建联合索引,这样扩展性太差肯定不能接受的。所以还有一种办法,手动回表。
5.3 手动回表
手动回表的前提是对order by 字段添加了索引
浅分页:
SELECT
user_no,
user_name,
score
FROM
student s1
JOIN ( SELECT id FROM student ORDER BY score DESC LIMIT 5, 20 ) s2 ON s1.id = s2.id
执行计划:

id 大的先执行
耗时:0.021s
深分页:
SELECT
user_no,
user_name,
score
FROM
student s1
JOIN ( SELECT id FROM student ORDER BY score DESC LIMIT 80000, 20 ) s2 ON s1.id = s2.id
执行计划:

耗时:0.042s
6 总结
| 优化方式 | 浅分页索引Type | 深分页索引Type | 浅分页耗时 | 深分页耗时 |
|---|---|---|---|---|
| 无 | All | All | 0.887s | 1.427s |
| order by 字段加索引 | index | All | 0.021s | 1.475s |
| 联合索引 | index | index | 0.024s | 0.047s |
| 手动回表(order by字段加索引) | index | index | 0.021s | 0.042s |
实战SQL优化(以MySQL深分页为例)的更多相关文章
- atitit。mssql sql server 转换mysql 及 分页sql ast的搭建
atitit.mssql sql server 转换mysql 及 分页sql ast的搭建 1. 主要的的转换::函数的转换,分页的转换 1 2. 思路::mssql sql >>as ...
- mysql的慢查询实战+sql优化
背景:使用A电脑安装mysql,B电脑通过xshell方式连接,数据内容我都已经创建好,现在我已正常的进入到mysql中 步骤1:设置慢查询日志的超时时间,先查看日志存放路径查询慢日志的地址,因为有慢 ...
- 查询效率提升10倍!3种优化方案,帮你解决MySQL深分页问题
开发经常遇到分页查询的需求,但是当翻页过多的时候,就会产生深分页,导致查询效率急剧下降. 有没有什么办法,能解决深分页的问题呢? 本文总结了三种优化方案,查询效率直接提升10倍,一起学习一下. 1. ...
- 正确使用索引(sql优化),limit分页优化,执行计划,慢日志查询
查看表相关命令 - 查看表结构 desc 表名- 查看生成表的SQL show create table 表名- 查看索引 show index from 表名 使用索引和不使用索引 由 ...
- 【SQL优化】MySQL官网中可优化的层次结构
正如上一篇中我翻译的那篇文章,关于MySQL数据库优化的宏观介绍,了解到了从大体上来讲,优化MySQL可以从3个角度来讲.那么这一篇文章,则从一个个优化点出发,统计出究竟有多少个地方我们可以来优化My ...
- SQL优化-大数据量分页优化
百万数据量SQL,在进行分页查询时会出现性能问题,例如我们使用PageHelper时,由于分页查询时,PageHelper会拦截查询的语句会进行两个步骤 1.添加 select count(*)fro ...
- MySQL 千万数据库深分页查询优化,拒绝线上故障!
文章首发在公众号(龙台的技术笔记),之后同步到博客园和个人网站:xiaomage.info 优化项目代码过程中发现一个千万级数据深分页问题,缘由是这样的 库里有一张耗材 MCS_PROD 表,通过同步 ...
- SQL优化---慢SQL优化
于2023.3.17日重写,之前写的还是太八股文太烂了一点逻辑都没有,这次重新写了之后,感觉数据库优化还是很有必要的,之前觉得不必要是我年轻了. 一.如何定位慢SQL语句 1.通过慢查询日志查询已经执 ...
- 工作中遇到的99%SQL优化,这里都能给你解决方案
前几篇文章介绍了mysql的底层数据结构和mysql优化的神器explain.后台有些朋友说小强只介绍概念,平时使用还是一脸懵,强烈要求小强来一篇实战sql优化,经过周末两天的整理和总结,sql优化实 ...
- mysql实战优化之一:sql优化
1.选取最适用的字段属性 MySQL 可以很好的支持大数据量的存取,但是一般说来,数据库中的表越小,在它上面执行的查询也就会越快.因此,在创建表的时候,为了获得更好的性能,我们可以将表中字段的宽度设得 ...
随机推荐
- 痞子衡嵌入式:在i.MXRT1xxx系列上用NAND型启动设备时可用两级设计缩短启动时间
大家好,我是痞子衡,是正经搞技术的痞子.今天痞子衡给大家分享的是在i.MXRT1xxx系列上用NAND型启动设备时可用两级设计缩短启动时间. 去年痞子衡写过一篇骚操作文章 <借助i.MXRT10 ...
- 力扣1097(MySQL)-游戏玩法分析Ⅴ(困难)
题目: 我们将玩家的安装日期定义为该玩家的第一个登录日. 我们还将某个日期 X 的第 1 天留存时间定义为安装日期为 X 的玩家的数量,他们在 X 之后的一天重新登录,除以安装日期为 X 的玩家的数量 ...
- Spring Cloud Bus 消息总线介绍
简介: 本文配套可交互教程已登录阿里云知行动手实验室,PC 端登录 start.aliyun.com 在浏览器中立即体验. 作者 | 洛夜来源 | 阿里巴巴云原生公众号 本文配套可交互教程已登录阿里云 ...
- GRPC: 如何实现分布式日志跟踪?
简介: 本文将介绍如何在 gRPC 分布式场景中,实现 API 的日志跟踪. 介绍 本文将介绍如何在 gRPC 分布式场景中,实现 API 的日志追踪. 什么是 API 日志追踪? 一个 API 请 ...
- 如何避免 Go 命令行执行产生“孤儿”进程?
简介: 在 Go 程序当中,如果我们要执行命令时,通常会使用 exec.Command ,也比较好用,通常状况下,可以达到我们的目的,如果我们逻辑当中,需要终止这个进程,则可以快速使用 cmd.Pro ...
- 表格存储 SQL 查询多元索引
简介: 多元索引是表格存储产品中一个重要的功能,多元索引使用倒排索引技术为表格存储提供了非主键列上的快速检索功能,另外也提供了统计聚合功能.表格存储近期开放了SQL查询功能,SQL引擎默认从原始表格 ...
- Oracle和达梦:获取更新随机时间sql
需求 1.修改数据库中表的创建.更新时间,日期固定,时间随机(日期也可以随机): 2.拿到这些sql去数据库执行就行了. 前提 -- 生成8-12间的随机数(小数) SELECT DBMS_RANDO ...
- Codeforces Good Bye 2023
A. 2023 正常签到. void solve() { int n, k, ok = 1; cin >> n >> k; int t = 2023; while(n --) ...
- XTuner 微调 LLM实操-书生浦语大模型实战营第二期第4节作业
这一作业中提及的解释比较少,更多的只是一些步骤截图.这是因为教程中已经提及了几乎所有的细节信息,没有什么需要补充的.这个页面相较于官方教程的部分解释得过于详细的内容甚至是有所删减的.比如关于文件路径可 ...
- Fiddler在抓取https数据包时如何解决Tunnel to 443的问题?
学习视频: https://www.bilibili.com/video/BV1zg4y1i7k3?p=2 谷歌浏览器导入证书 1.导出证书到桌面 2.双击安装证书 3.浏览器-->设置--&g ...