首页 > 数据库 >实战SQL优化(以MySQL深分页为例)

实战SQL优化(以MySQL深分页为例)

时间:2023-03-30 18:24:14浏览次数:45  
标签:分页 为例 SQL 回表 索引 score user MySQL NULL

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,回表,索引,score,user,MySQL,NULL
From: https://www.cnblogs.com/Fzeng/p/17273915.html

相关文章

  • MySQL常用命令
    常用命令:https://blog.csdn.net/qq_38328378/article/details/80858073最详细的:https://blog.csdn.net/qq_34115899/article/details/81190461......
  • MySQL数据库怎么创建表?MySQL数据库基础知识
    MySQL是一个关系型数据库管理系统,由瑞典MySQLAB公司开发,目前属于Oracle旗下产品。MySQL最流行的关系型数据库管理系统,在WEB应用方面MySQL是最好的RDBMS(RelationalDatabaseManagementSystem,关系数据库管理系统)应用软件之一。MySQL是一种关联数据库管理系统,关联数据库......
  • 22、MySQL主从复制详解及配置
    主从复制的介绍MySQL主从复制是指将一个MySQL服务器的数据复制到其他MySQL服务器上的过程。在主从复制中,一个MySQL服务器(称为“主服务器”或“主节点”)充当源,另一个或多个MySQL服务器(称为“从服务器”或“从节点”)充当目标。主服务器将更新和更改记录到二进制日志(binaryl......
  • 常见SQL总结二
    --查询没有学全所有课的同学的学号、姓名;SELECTsid,snameFROMstudentstu,(SELECTCOUNT(sid)asnum,student_idFROMscoreGROUPBYstudent_id)t1,--查出每个人的学习课程数量(SELECTCOUNT(cid)asnumFROMcourse)t2--再查出所有课程数量WHEREt2.num>t1.numand......
  • 查看 SQL Server 当前的连接数
    打开SQLServerManagementStudio(SSMS),连接到SQLServer实例。在SSMS的“对象资源管理器”窗格中,展开服务器节点。点击“管理”文件夹,然后选择“活动连接”。在“......
  • MySQL、Redis和Elasticsearch比较
    MySQL是一种关系型数据库管理系统,它被广泛用于存储结构化数据。拥有极高的可靠性和安全性,支持ACID事务,并具有良好的扩展性,可以适应高并发访问的场景。Redis是一种内存......
  • MySql基本的简单sql语句
    SQL语句分类必须记住删除语句DELETEFROM表名WHERE条件插入语句简单的插入语句INSERTINTO表名(字段列表)VALUES(值列表)查询出的数据插入到已存在的表中查询出的数......
  • Mybatis动态SQL映射
    Mybatis动态SQL映射动态SQL映射1.if结构test里面的and或or必须小写2.trim-if多条件结构3.where-if多条件结构4.choose-when-otherwise多选一结构5.foreach循环结......
  • MySQL导入数据库1118错误解决方案[ERR] 1118 - Row size too large (> 8126). Changing
    MySQL导入数据库1118错误解决方案[ERR]1118-Rowsizetoolarge(>8126).ChangingsomecolumnstoTEXTorBLOB编辑sql文件,在开头设置一下innodb_strict_mode为0SE......
  • 拒绝“爆雷”!GaussDB(for MySQL)新上线了这个功能
    摘要:智能把控大数据量查询,防患系统奔溃于未然。本文分享自华为云社区《拒绝“爆雷”!GaussDB(forMySQL)新上线了这个功能》,作者:GaussDB数据库。什么是最大读取行一直以来,大......