MySQL深分页问题及三种解决方案

 更新时间:2023年06月15日 10:38:07   作者:JAVA前线  
本文主要介绍了MySQL深分页问题及三种解决方案,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧

1 深分页问题

1.1 创建表

CREATE TABLE `player` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键',
  `player_id` varchar(256) NOT NULL COMMENT '运动员编号',
  `player_name` varchar(256) NOT NULL COMMENT '运动员名称',
  `height` int(11) NOT NULL COMMENT '身高',
  `weight` int(11) NOT NULL COMMENT '体重',
  `game_performance` text COMMENT '最近一场比赛表现',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8

1.2 新增100万条数据

@SpringBootTest(classes = TestApplication.class)
@RunWith(SpringJUnit4ClassRunner.class)
public class PlayerServiceTest {
    @Resource
    private PlayerRepository playerRepository;
    @Test
    public void initBigData() {
        for (int i = 0; i < 1000000; i++) {
            PlayerEntity entity = new PlayerEntity();
            entity.setPlayerId(UUID.randomUUID().toString());
            entity.setPlayerName("球员_" + System.currentTimeMillis());
            entity.setWeight(150);
            entity.setHeight(188);
            entity.setGamePerformance("{\"runDistance\":8900.0,\"passSuccess\":80.12,\"scoreNum\":3}");
            playerRepository.insert(entity);
        }
    }
}

1.3 深分页语句

select * from player limit 990000,5

1.4 结果分析

查询耗时:1.233秒

本语句目标查询[990001-990005]五条数据

但是执行时需要排序[1-990005]数据

最终丢弃[1-990000]只返回[990001-990005]数据

2 深分页优化方案

2.1 方案一

我们可以从业务形态维度去解决,可以参考搜索引擎解决方案。因为ES也存在深分页问题,搜索引擎解决方案是在业务上会限制查询页数。因为页数越大,内容相关度越低,所以页数太大对业务价值不高。MySQL可以类比处理:

  • 限制查询页数
  • 限制全量导出
  • 查询时要求带必要条件(时间范围、userId)

2.2 方案二

2.2.1 优化语句

select * from player a, (select id as tmpId from player limit 990000,5) b WHERE a.id = b.tmpId复制代码

2.2.2 执行计划

(1) 查看计划

explain select * from player a, (select id as tmpId from player limit 990000,5) b WHERE a.id = b.tmpId复制代码

01 深分页优化方案1.jpg

(2) 执行顺序

  • id越大执行顺序越靠前
  • id相同则按照行数从上到下执行
  • 本语句执行顺序如下图:

02 深分页优化方案2_执行顺序.jpg

  • 第一步和第二步表示执行子查询
  • 第三步表示player表与子查询关联

(3) explain type

访问类型是重要分析指标:

03 explain_type.jpg

(4) explain Extra

Extra表示执行计划扩展信息重点关注三个:

04 explain extra.jpg

2.2.3 结果分析

  • 查询耗时:0.5秒
  • 原因是覆盖索引提升分页查询效率(只查询ID列)
  • 覆盖索引含义是查询时索引列完全包含查询列
  • using index表示使用覆盖索引,性能提升

2.3 方案三

2.3.1 优化语句

select * from player where id > 990000 LIMIT 5复制代码

2.3.2 执行计划

(1) 查看计划

explain select * from player where id > 990000 LIMIT 5复制代码

05 深分页优化方案2.jpg

(2) 结果分析

  • 查询耗时:0.001秒
  • range表示索引范围搜索性能尚可

(3) 适用场景

  • 不适用跳页场景
  • 只适用【上一页】【下一页】场景

3 MyBatis

<mapper namespace="com.test.java.front.test.mysql.deep.page.repository.PlayerRepository">
	<resultMap id="BaseResultMap" type="com.test.java.front.test.mysql.deep.page.entity.PlayerEntity">
		<id column="id" jdbcType="BIGINT" property="id" />
		<result column="player_id" jdbcType="VARCHAR" property="playerId" />
		<result column="player_name" jdbcType="VARCHAR" property="playerName" />
		<result column="height" jdbcType="INTEGER" property="height" />
		<result column="weight" jdbcType="INTEGER" property="weight" />
		<result column="game_performance" jdbcType="LONGVARCHAR" property="gamePerformance" />
	</resultMap>
	<sql id="Base_Column_List">
		id, player_id, player_name, height, weight, game_performance
	</sql>
	<sql id="conditions">
		<where>
			<if test="playerId != null">
				and player_id = #{playerId,jdbcType=VARCHAR}
			</if>
		</where>
	</sql>
	<sql id="pager">
		<if test="skip != null and limit != null">
			limit #{skip}, #{limit}
		</if>
	</sql>
	<!-- 查询条数 -->
	<select id="selectPageCount" parameterType="com.test.java.front.test.mysql.deep.page.param.biz.PlayerQueryParam" resultType="java.lang.Long">
		select count(*) from player
		<include refid="conditions" />
	</select>
	<!-- 分页方式1:普通分页存在深分页问题 -->
	<!-- select * from player limit 990000,5 -->
	<select id="selectPager1" parameterType="com.test.java.front.test.mysql.deep.page.param.biz.PlayerQueryParam" resultMap="BaseResultMap">
		select
		<include refid="Base_Column_List" />
		from player
		<include refid="conditions" />
		<include refid="pager" />
	</select>
	<!-- 分页方式2:覆盖索引优化深分页问题 -->
	<!-- select * from player a, (select id as tmpId from player limit 990000,5) b where a.id = b.tmpId -->
	<select id="selectPager2" parameterType="com.test.java.front.test.mysql.deep.page.param.biz.PlayerQueryParam" resultMap="BaseResultMap">
		select
		<include refid="Base_Column_List" />
		from player a,
		(
		select id as tmpId from player
		<include refid="conditions" />
		<include refid="pager" />
		) b
		where a.id = b.tmpId
	</select>
	<!-- 分页方式3:Id分页不支持跳页 -->
	<!-- select * from player where id > 990000 limit 5 -->
	<select id="selectPager3" parameterType="com.test.java.front.test.mysql.deep.page.param.biz.PlayerQueryIdParam" resultMap="BaseResultMap">
		select
		<include refid="Base_Column_List" />
		<include refid="conditions" />
		from player where id > #{startId} limit #{pageSize}
	</select>
</mapper>

4 文章总结

本文第一介绍深分页问题表现和原因。第二介绍深分页问题三种解决方法,方案一是从业务维度优化,方案二是使用覆盖索引进行优化,方案三是使用Id分页。第三展示MyBatis相关代码。

到此这篇关于MySQL深分页问题及三种解决方案的文章就介绍到这了,更多相关MySQL深分页内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • 一些mysql启动参数的说明和优化方法

    一些mysql启动参数的说明和优化方法

    要求MySQL能有的连接数量。当主要MySQL线程在一个很短时间内得到非常多的连接请求,这就起作用,然后主线程花些时间(尽管很短)检查连接并且启动一个新线程。
    2011-04-04
  • MyISAM和InnoDB引擎优化分析

    MyISAM和InnoDB引擎优化分析

    这几天在学习mysql数据库的优化并在自己的服务器上进行设置,喻名堂主要学习了MyISAM和InnoDB两种引擎的优化方法,需要了解跟多的朋友可以参考下
    2012-11-11
  • win10下MySQL 8.0登录Access denied for user‘root’@‘localhost’ (using password: YES)问题的解决方法

    win10下MySQL 8.0登录Access denied for user‘root’@‘localhost’ (u

    这篇文章主要介绍了win10下MySQL 8.0登录Access denied for user‘root’@‘localhost’ (using password: YES)问题的解决方法,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2019-03-03
  • Windows Server 2003 下配置 MySQL 集群(Cluster)教程

    Windows Server 2003 下配置 MySQL 集群(Cluster)教程

    这篇文章主要介绍了Windows Server 2003 下配置 MySQL 集群(Cluster)教程,本文先是讲解了原理知识,然后给出详细配置步骤和操作方法,需要的朋友可以参考下
    2015-06-06
  • MySQL性能优化之分区表的使用详解

    MySQL性能优化之分区表的使用详解

    在当今数据驱动的时代,大型数据库的性能优化对于企业的成功至关重要,本文将深入探讨MySQL分区表的基础知识、性能优势、分区策略的选择和实施等内容,感兴趣的小伙伴可以了解一下
    2023-06-06
  • 亲手教你SQLyog12.08安装详细教程

    亲手教你SQLyog12.08安装详细教程

    SQLyog 是一个快速而简洁的图形化管理MYSQL数据库的工具,它能够在任何地点有效地管理你的数据库,这篇文章主要介绍了SQLyog12.08安装详细教程,需要的朋友可以参考下
    2023-04-04
  • MySQL 开启慢查询日志的方法

    MySQL 开启慢查询日志的方法

    本篇文章主要介绍了MySQL 开启慢查询日志的方法,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2017-06-06
  • Linux中安装MySQL5.7.42的详细教程

    Linux中安装MySQL5.7.42的详细教程

    这篇文章主要介绍了Linux中安装MySQL5.7.42,本文通过实例图文并茂的形式给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2023-09-09
  • 解决sql server不支持variant数据类型的问题

    解决sql server不支持variant数据类型的问题

    在数据库中,数据类型是非常重要的,但有时候我们可能会遇到 SQL Server 不支持的数据类型,例如 Variant,在本篇博文中,我们将探讨问题的背景,提供解决思路,并总结如何解决 SQL Server 不支持 Variant 数据类型的挑战
    2023-09-09
  • 浅析MySQL索引结构采用B+树的问题

    浅析MySQL索引结构采用B+树的问题

    数据库的存储引擎都是采用B树或者B+树来实现索引的存储,总体来说,我认为技术方案的选型,更多的要根据具体的业务场景来决定,并不一定是说B+树就是最好的选择,就像MongoDB里面采用B树结构,本文介绍我对MySQL索引结构采用B+树的理解
    2022-06-06

最新评论