mysql查询的原始返回顺序与limit分页优化

mysql查询时每条记录的原始返回顺序

mysql 查询时每条记录的原始返回顺序,由此sql语句的执行计划和内部存储引擎的实现决定【跟实现细节有关,跟sql语义无关=>不是 接口契约 即在sql语义上来说是未定义的】=>只有查询时加了 order by 后才根据order by字段 升序或者降序返回

即 原始返回顺序,由 MySQL 在该次查询中选择的"访问路径(access path)"决定,而不是 SQL 语义决定。

受执行计划的影响:

如果执行计划是 主键索引扫描:返回顺序 ≈ 主键 B+Tree 的叶子节点顺序【而不是插入到表时顺序】

如果 MySQL 走的是 二级索引:顺序是:二级索引 key 顺序 + 主键值顺序【而不是插入到表时顺序】

如果一条sql语句本身虽然没变,但是执行计划变了,比如索引变动;原始查询(不加order by 的查询)的返回顺序也会变

limit分页查询优化

LIMIT offset, count 在 offset 很大时变慢,是因为 MySQL 必须"先找到并丢弃 offset 行",这些工作量不会因为 LIMIT 而减少。

即mysql必须根据执行计划先找到前offset行 再丢弃;=>跟是否加索引无关,无论是否加索引都是先要找到前offset行 再丢弃 =>LIMIT 只限制返回行数,不限制扫描行数。

优化方案:

1.游标分页

如果能确定offset那一行的某个唯一列的值(比如自增主键ID),可以用 WHERE 子句来代替 OFFSET,从而避免扫描和丢弃大量行。 以及保证查询得到返回顺序结构不变【比如使用order by 前面的那个唯一的列】=>就可以使用 游标分页

SELECT *

FROM t

WHERE id > last_id 【范围查询】

ORDER BY id

LIMIT 20;

游标分页的条件是:只要使用范围查询的键(字段)满足 全序,稳定,可比较,唯一性 即可【不要求该键必须连续自增】=>雪花算法生成的ID 是可以的

2.覆盖索引+回表查询=>通常是在子查询中先使用 覆盖索引查询进行limit分页查询,虽然此时子查询中依然需要扫描offset的条数,但是因为是覆盖索引扫描,扫描效率高很多;然后再通过主键回表查询完整记录=>【即外部的查询通过子查询的结果进行回表查询查询完整数据】

相当于大量的offset扫描是在覆盖索引上进行的,回表查询只查询少量数据

SELECT *

FROM t

WHERE id IN (

SELECT id

FROM t

ORDER BY id

LIMIT 1000000, 20

)

ORDER BY id;

3.不允许用户查询过大的offset,必须通过时间,状态,关键字等条件进行过滤,只查询过滤后的数据减少offset的大小=>相当于一种泛化(模糊)版的游标分页

相关推荐
于眠牧北20 小时前
MySQL的锁类型,表锁,行锁,MVCC中所使用的临键锁
mysql
Turnip12023 天前
深度解析:为什么简单的数据库"写操作"会在 MySQL 中卡住?
后端·mysql
加号33 天前
windows系统下mysql多源数据库同步部署
数据库·windows·mysql
シ風箏3 天前
MySQL【部署 04】Docker部署 MySQL8.0.32 版本(网盘镜像及启动命令分享)
数据库·mysql·docker
WeiXin_DZbishe4 天前
基于django在线音乐数据采集的设计与实现-计算机毕设 附源码 22647
javascript·spring boot·mysql·django·node.js·php·html5
爱可生开源社区4 天前
MySQL 性能优化:真正重要的变量
数据库·mysql
小马爱打代码4 天前
MySQL性能优化核心:InnoDB Buffer Pool 详解
数据库·mysql·性能优化
风流 少年4 天前
mysql mcp
数据库·mysql·adb
西门吹雪分身4 天前
mysql之数据离线迁移
数据库·mysql
轩情吖4 天前
MySQL初识
android·数据库·sql·mysql·adb·存储引擎