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

相关推荐
`Levie2 小时前
MySQL-数据库服务日志管理与数据闪回
数据库·mysql
香蕉大香蕉(06敬畏市场)2 小时前
MySQL 单点详解(01)
java·数据库·mysql·面试·博客·实习
吹什么轩3 小时前
MySQL 事务管理:从 ACID 到 MVCC,一篇讲透
数据库·mysql
paopaokaka_luck4 小时前
基于springboot+vue的益暖微光公益服务平台(DeepSeek公益助手、善款信息追溯、志愿服务积分闭环、ECharts运营分析、活动状态自动流转)
java·前端·javascript·spring boot·mysql·架构·echarts
m0_639906944 小时前
MySQL 锁机制详解|表锁、行锁、意向锁,死锁成因与解决方案
数据库·mysql
进击的荆棘4 小时前
MySQL——在ubuntu环境下安装MySQL
数据库·mysql·ubuntu
夜雪一千4 小时前
MySQL 数据字典如何获得
数据库·mysql
honsor4 小时前
用 Grafana 做温湿度异常检测:从阈值告警到趋势预测
数据库·mysql·php
lusklusklusk5 小时前
SQL Server 为什么普通 SELECT 会阻塞 UPDATE?——行级 S 锁到表级 S 锁的锁升级原理与实验验证
数据库·mysql·oracle
程序员塔塔喵6 小时前
【MySQL篇|第十而二篇】深层次讲解MVCC机制
mysql·mvcc