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的大小=>相当于一种泛化(模糊)版的游标分页

相关推荐
摇滚侠15 小时前
MySQL 中 utf8mb4 字符集,字母a占几个字节,一个汉字占几个字节 / MySQL 中 utf8mb3 字符集,字母a占几个字节,一个汉字占几个字节
数据库·mysql
Antoine-zxt16 小时前
MySQL CPU飙升至500%的深度排查与优化实践
数据库·mysql
Awkwardx16 小时前
MySQL数据库—MySQL基本查询
数据库·mysql
让你三行代码QAQ16 小时前
MySQL全方位优化方案
mysql
大爱编程♡17 小时前
Spring IoC&DI
数据库·mysql·spring
周末吃鱼19 小时前
MySQL CTE:SQL查询新模式
数据库·sql·mysql
HL计算机菜鸟19 小时前
一对多的实现关系 在数据库表中多的一方添加字段,来关联一的一方主键
mysql
Psycho_MrZhang20 小时前
MySQL/PgSQL设计思想总结
数据库·mysql
风吹落叶花飘荡20 小时前
将mysql数据库的内容备份至阿里云 oss归档存储
数据库·mysql·阿里云