SQL分页查询方案的性能对比[通俗易懂]

SQL分页查询方案的性能对比[通俗易懂]作者|中国农业银行吴海存责编|晋兆雨头图|CSDN下载自视觉中国导读本文主要介绍了基于ROWNUM、主键列/非空唯一性列、分析函数、OFFSET-FETCHNEXT机制的…

大家好,又见面了,我是你们的朋友全栈君。

SQL分页查询方案的性能对比[通俗易懂]

SQL分页查询方案的性能对比[通俗易懂]

作者 | 中国农业银行 吴海存

责编 | 晋兆雨

头图 | CSDN下载自视觉中国

SQL分页查询方案的性能对比[通俗易懂]

导读

本文主要介绍了基于ROWNUM、主键列/非空唯一性列、分析函数、OFFSET-FETCH NEXT机制的几种SQL分页查询方案的性能对比。

分页查询可分为逻辑分页和物理分页两种。逻辑分页是应用代码级别实现的分页,指用户通过一次查询就取出所有的数据结果集并进行缓存,然后根据当前页所需要展示的数据内容进行切分并遍历显示,若需要查询的数据量非常大,则会消耗大量的内存来缓存数据,并且在会话生命周期内重复访问数据时,可直接访问缓存的数据,不过此时有可能访问不到最新的数据。物理分页是指使用数据库自带的分页机制,比如MySQL的limit offset机制,Oracle的rownum和offset-fetch机制进行分页查询,是对数据库表数据进行分页条件查询,每一次物理分页都会直接访问数据库,可以保证数据是最新的,并且不需要在会话级别缓存过多的数据。

本文主要介绍的SQL分页,即物理分页,主要用于在数据结果集较大时控制数据在前台(比如报表,列表框,页面等)的分页显示,这样既可以降低内存消耗,提高查询效率,也可以方便数据在前台的展示。文中如有疏漏之处,望指正!

SQL分页查询方案的性能对比[通俗易懂]

环境版本信息

  • Oracle 版本:19.3.0.0.0

  • MySQL版本:8.0.18

  • OS版本:CentOS 8.0

SQL分页查询方案的性能对比[通俗易懂]

方案及性能对比

1.确认测试表emp中的数据量

SQL分页查询方案的性能对比[通俗易懂]

2.确认表结构和索引信息

SQL分页查询方案的性能对比[通俗易懂]

3.通过rownum实现分页查询(不使用order by排序)

SQL: select * from ( select rownum rowno,e.* from emp e where rownum<=&ROW_NUM1) t where t.rowno>=&ROW_NUM2;

 执行计划信息:

SQL分页查询方案的性能对比[通俗易懂]

SQL分页查询方案的性能对比[通俗易懂]

通过执行计划和评估开销可以看出,该方法将使用全表扫描,前段的分页查询效率会比较高,但是随着ROWNUM值的增大,在分页后期查询的速度会越来越慢,这个情况和MySQL的limit机制一样,当表中数据量较大时,随着查询范围的扩大,每次需要读取的表数据块越来越多,查询效率越来越低。如下图所示:

SQL分页查询方案的性能对比[通俗易懂]

SQL分页查询方案的性能对比[通俗易懂]

 

4.通过rownum实现分页查询(使用order by排序)

SQL: select * from ( select rownum rowno,e.* from (select * from emp order by id) e where rownum<=&2) t where t.rowno>=&1;

执行计划信息:

SQL分页查询方案的性能对比[通俗易懂]

SQL分页查询方案的性能对比[通俗易懂]

由执行计划信息可以看出,当使用order by对数据集进行排序后再分页时,由于索引数据在存储的时候默认已经进行了升序排序(若有需要,也可以创建降序索引,该案例是基于Oracle环境,对于MySQL数据库,从8.0开始也支持了真正意义的降序索引),因此使用了索引全扫描(即索引遍历)来避免排序,后期需要遍历的索引块越来越多,并且由于index full scan是单块读,所以该方法会出现在分页后期查询效率越来越慢的情况。如下图所示:

SQL分页查询方案的性能对比[通俗易懂]

5.直接使用主键代替ROWNUM进行分页查询

查出id的最大值和最小值:

SQL分页查询方案的性能对比[通俗易懂]

SQL: select * from emp where id between &1 and &2;

执行计划信息: 

SQL分页查询方案的性能对比[通俗易懂]

SQL分页查询方案的性能对比[通俗易懂]

从执行计划信息可以看出,该方法使用了主键索引的range scan,当表数据量较大时,不会出现随着查询范围的扩大而查询效率越来越低的情况,因为可以直接通过主键或非空唯一性索引读取到符合条件的rowid,然后直接通过rowid找到数据块读取数据,如下图所示:

SQL分页查询方案的性能对比[通俗易懂]

说明:

  • 该方法需要主键值是连续的,否则有可能出现分页查询时每一页的数据行数不一样的情况。

  • 假如表上有其他的非空唯一性索引列,则同样可以基于该列做分页查询。

  • 若在分页查询时表上有一定的DML操作,则可以考虑进行最后一页查询时将SQL中的变量2设置较大一些(也可以通过子查询直接获取max(id))。

6.使用分析函数进行分页查询

SQL: select * from ( select e.*, row_number() over (order by id) rn from emp e) where rn between &1 and &2; 

执行计划信息:

SQL分页查询方案的性能对比[通俗易懂]

SQL分页查询方案的性能对比[通俗易懂]

从执行计划信息可以看出,该方法使用了窗口函数进行分页查询,同样使用了INDEX FULL SCAN来避免排序,该方法也会出现在分页后期查询效率越来越慢的情况,因为后期需要遍历的索引块越来越多,并且由于index full scan是单块读,因此后期的效率有可能会比使用ROWNUM的方式更为低下,如下图所示:

SQL分页查询方案的性能对比[通俗易懂]

SQL: select * from emp order by id OFFSET &1 ROWS FETCH NEXT &2 ROWS ONLY;

执行计划信息:

SQL分页查询方案的性能对比[通俗易懂]

SQL分页查询方案的性能对比[通俗易懂]

从执行计划可以看出,offset-fetch机制在底层本质上还是基于分析函数实现的,同样使用了索引全扫描(即索引遍历)来避免排序,因此该方法也会出现在分页后期查询效率越来越慢的情况,因为后期需要遍历的索引块越来越多,并且由于index full scan是单块读,从而产生的物理IO和逻辑IO次数更多,因此后期的效率有可能会比使用ROWNUM的方式更为低下,如下图所示: 

SQL分页查询方案的性能对比[通俗易懂]

8.排序列的选择

当列可为NULL时,Oracle不能使用该列上的索引来避免排序,因为Oracle的索引是不记录NULL值的,如下图所示:

SQL分页查询方案的性能对比[通俗易懂]

SQL分页查询方案的性能对比[通俗易懂]

通过对比分析,我们可以得出如下结论:

1.当主键值或者非空唯一性列值是连续时,推荐使用主键值或者非空唯一性列进行分页,此时分页效率较高且数据量较大时分页后期性能不会越来越差。

2.当对分页后每页的数据行数没有较高要求时,同样推荐使用主键值或者非空唯一性列进行分页。

3.使用分析函数和OFFSET-FETCH实现分页,分页后期的性能衰减率可能会比通过ROWNUM的方式高,这是因为index full scan是单块读,从而产生了更多次的物理IO和逻辑IO。

4.在使用分析函数和OFFSET-FETCH机制时,需要基于主键或非空唯一性列进行order by排序,此时会通过列上的索引来避免排序操作。若选择的排序列可为NULL,则Oracle数据库只能通过全表扫描来访问数据,因为Oracle数据库的索引是不记录NULL值的,因此不能基于该列上的索引来避免排序,从而保证不会丢失数据。

5.在MySQL中,索引是会记录NULL值的,这也是为什么MySQL中IS NULL可以走索引的原因。

6.MySQL数据库的分页中,可以使用可为null的非唯一性列作为排序列,因为此时MySQL会将null值当作最小值参加排序,不会丢失数据。

作者介绍:

吴海存,10g/11g/12c OCM, Oracle Exadata/Golden Gate 专家, 曾于Amazon和Oracle公司担任全球业务资深DBA,目前供职于中国农业银行,担任资深数据库专家。

SQL分页查询方案的性能对比[通俗易懂]

更多阅读推荐

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/153255.html原文链接:https://javaforall.cn

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)
blank

相关推荐

  • html注册cab包,OCX控件打包成CAB并实现数字签名过程

    html注册cab包,OCX控件打包成CAB并实现数字签名过程OCX打包CAB并签名过程一、打包cab制作cab文件时需要将所有的相关文件都包含进去,可以通过Depends(VC自带的)检查需要的文件。使用inf文件将这些东西都写进去。1、制作inf文件default.INF最开始一般是[Version]区:eg:[Version]signature=”$CHICAGO$”AdvancedINF=2.0接下来就是最重要的[Add.Code]区:eg:…

  • acwing1068. 环形石子合并(区间dp+前缀和)「建议收藏」

    acwing1068. 环形石子合并(区间dp+前缀和)「建议收藏」将 n 堆石子绕圆形操场排放,现要将石子有序地合并成一堆。规定每次只能选相邻的两堆合并成新的一堆,并将新的一堆的石子数记做该次合并的得分。请编写一个程序,读入堆数 n 及每堆的石子数,并进行如下计算:选择一种合并石子的方案,使得做 n−1 次合并得分总和最大。选择一种合并石子的方案,使得做 n−1 次合并得分总和最小。输入格式第一行包含整数 n,表示共有 n 堆石子。第二行包含 n 个整数,分别表示每堆石子的数量。输出格式输出共两行:第一行为合并得分总和最小值,第二行为合并得分总和最大

  • Sublime Text3使用Package Control 报错There Are No Packages Available For Installation

    Sublime Text3使用Package Control 报错There Are No Packages Available For Installation在使用sublime时,有时候我们希望将代码复制出来后仍然是高亮显示,这样我们便需要安装SublimeHighLight插件,在安装SublimeHighLight插件之前,我们应该先安装PackageControl插件!1、PackageControl插件作用:能够利用这个插件安装很多Sublime的插件!2、SublimeHighLight插件作用:能让代码更好地展示其高亮性!我先从网上

  • 35 个 Java 代码性能优化总结 10-20「建议收藏」

    35 个 Java 代码性能优化总结 10-20

  • mac 安装golang2021 激活码_在线激活

    (mac 安装golang2021 激活码)2021最新分享一个能用的的激活码出来,希望能帮到需要激活的朋友。目前这个是能用的,但是用的人多了之后也会失效,会不定时更新的,大家持续关注此网站~IntelliJ2021最新激活注册码,破解教程可免费永久激活,亲测有效,下面是详细链接哦~https://javaforall.cn/100143.html…

  • php ajax parsererror,完美解决ajax跨域请求下parsererror的错误

    php ajax parsererror,完美解决ajax跨域请求下parsererror的错误这篇文章主要为大家详细介绍了完美解决ajax跨域请求下parsererror的错误,具有一定的参考价值,可以用来参考一下。感兴趣的小伙伴,下面一起跟随512笔记的小编两巴掌来看看吧!ajax请求报parsererror错误是很宽泛的概念,很多情况下都报这个错,在很多时候,即使ajax提交、返回都正常XMLHttpRequest.status=200(正常响应)XMLHttpRequest.re…

发表回复

您的电子邮箱地址不会被公开。

关注全栈程序员社区公众号