找回密码
立即注册
搜索
热搜: Java Python Linux Go
发回帖 发新帖

4323

积分

0

好友

607

主题
发表于 2 小时前 | 查看: 2| 回复: 0

数据库分页查询功能是处理大量数据时常用的技术,将结果集分成多个“页”返回,提高系统性能和用户体验。以下是关键要点:  

  • 性能优化:避免一次性加载全部数据,减少内存消耗和网络传输  
  • 提升响应速度:快速返回首屏数据  
  • 改善用户体验:支持逐页浏览大数据集  
  • 未分页的结果集一般比较大  
  • 页码小的查询快,随着页码增大,会越来越慢  

YashanDB 23.5 针对分页查询场景进行了专项优化,核心是 Rownum/StopKey 的下推能力。本文基于真实测试环境,以 Oracle 19c 为参照系,从七类典型分页 SQL 入手,深入剖析执行计划、IO 消耗与耗时差异,揭示不同实现方式下的性能边界。

YashanDB 23.5 TP+性能提升:分页查询场景的Rownum/StopKey下推优化

测试结果总览

YashanDB与Oracle在七种分页查询场景下的性能对比表格

表格说明:横轴为测试场景编号与 SQL 类型,纵轴为 Oracle 19.3 与 YashanDB 23.5 的 IO 指标(consistent gets / db block gets)及耗时;“说明”列标注了性能优劣与异常点。


测试场景一:无谓词分页查询

测试语句

ALTER SESSION SET statistics_level=ALL;
set timing on
SET autotrace ON;
select * from(
 select a.*,rownum as rn from (
   select object_id from t1 order by object_id desc
 )
a) where rn > 10 and rn < 20;

Oracle 测试结果
执行耗时:3.05秒,IO:172694 consistent gets
执行计划关键路径:TABLE ACCESS FULL → SORT ORDER BY
统计信息显示大量物理读(14654 physical reads),说明全表扫描后需排序再截取,效率低下。

YashanDB 测试结果
执行耗时:0.020秒,IO:2 db block gets
执行计划关键路径:INDEX FULL SCAN DESCENDING + COUNT STOPKEY
无任何 consistent gets,且 Predicate Information 明确显示 ROWNUM > 10ROWNUM < 20 被下推至索引扫描层。

小结  

  • 场景一中 YashanDB 性能显著占优(150 倍提速)  
  • 根本原因在于:Oracle 索引不存储 NULL 值,而 YashanDB 索引包含所有列值(含 NULL),因此可直接走索引扫描,无需回表或全表扫描  
  • 该场景对 Oracle 不公平,故后续引入谓词进一步验证

索引概述:YashanDB索引包含表的索引列的所有数据(包括NULL)


测试场景二:有谓词分页查询

测试语句

ALTER SESSION SET statistics_level=ALL;
set timing on
SET autotrace ON;
select * from(
 select a.*,rownum as rn from (
   select object_id from t1 where object_id is not null order by object_id desc
 )
a) where rn > 10 and rn < 20;

Oracle 测试结果
耗时:3.16秒,IO:20913 consistent gets
执行计划已启用 INDEX FULL SCAN DESCENDING,但因 COUNT STOPKEY 未完全下推(仍需构造完整中间结果集),IO 与耗时仍偏高。

YashanDB 测试结果
耗时:0.003秒,IO:2 db block gets
执行计划中 COUNT STOPKEY 出现在第 2 步,且 INDEX RANGE SCAN DESCENDING 精准命中谓词条件;Predicate Information 显示 access("T1"."OBJECT_ID" IS NOT NULL) 已下推至索引访问层。

小结  

  • YashanDB 在有谓词场景下仍保持压倒性优势(超 1000 倍提速)  
  • Rownum/StopKey 下推 在 YashanDB 中已深度集成至优化器,配合谓词可实现“边扫描边裁剪”,极大降低资源开销  
  • 但该 SQL 写法存在潜在风险——嵌套过深易导致优化器误判,建议改用三层结构(见场景三)

测试场景三:三层分页查询

测试语句

select * from(
 select a.*,rownum as rn from (
   select object_id from t1 where object_id is not null order by object_id desc
 )a where rownum < 20
) where rn > 10 ;

Oracle 测试结果
耗时:0.01秒,IO:4 consistent gets
执行计划中 COUNT STOPKEY 出现在第 2 步,INDEX FULL SCAN DESCENDING 直接完成前 20 行扫描,再由外层过滤 rn > 10,逻辑清晰高效。

YashanDB 测试结果
耗时:0.006秒,IO:2 db block gets
执行计划同样使用 COUNT STOPKEY + INDEX RANGE SCAN DESCENDING,且 A-RowsE-Rows 高度吻合,表明估算精准、执行稳定。

小结  

  • Oracle 与 YashanDB 在此场景下性能基本相当(YashanDB 略快)  
  • 二者均成功将 STOPKEY 下推至索引扫描阶段,验证了 Rownum/StopKey 优化在主流写法中的普适性  
  • 场景一、二中 Oracle 表现不佳,本质是 SQL 编写方式未触发其优化路径,而非内核能力缺失

测试场景四:分析函数分页查询

测试语句

select * from(
  select object_id,row_number() over (order by object_id desc) as rn 
  from t1 where object_id is not null
) where rn > 10 and rn < 20;

Oracle 测试结果
耗时:0.01秒,IO:4 consistent gets
执行计划:WINDOW NOSORT STOPKEY + INDEX FULL SCAN DESCENDINGStopKey: 19 明确生效,全程免排序。

YashanDB 测试结果
耗时:3.182秒,IO:17576 db block gets
执行计划中虽有 WINDOW NOSORT,但缺少 * 标记的 STOPKEY 步骤;多出 |* 2 |   RESULT 层,且 A-Time3163259(微秒级),表明窗口函数实际执行了全量计算后裁剪。

小结  

  • Oracle 在分析函数分页上表现更优,YashanDB 当前版本对此类语法的 STOPKEY 下推支持尚不完善  
  • 关键差异:Oracle 的 WINDOW NOSORT STOPKEY 可提前终止,而 YashanDB 的 WINDOW NOSORT 未做行数限制,导致全量扫描后过滤  
  • 若业务强依赖 ROW_NUMBER() 分页,建议优先采用三层 rownum 结构替代

测试场景五:OFFSET 分页查询(含 rownum)

测试语句

select object_id,rownum as rn
from t1 where object_id is not null order by object_id desc
offset 10 rows fetch next 9 rows only;

Oracle 测试结果
耗时:0.01秒,IO:4 consistent gets
执行计划:WINDOW NOSORT STOPKEY + INDEX FULL SCAN DESCENDINGStopKey: 19 生效,逻辑与场景四一致。

YashanDB 测试结果
耗时:7.065秒,IO:17576 db block gets
执行计划中 ORDER BY STOPKEY 存在,但 A-Rows20(非预期的 9),且 RN 返回值异常(如 9999989),说明 rownum 生成逻辑与 OFFSET/FETCH 未协同,实际执行了全量排序后截取。

小结  

  • YashanDB 当前对 OFFSET ... FETCH + rownum 混合写法兼容性不足,结果与 Oracle 不一致  
  • RN 值巨大(接近总行数)暴露其内部先生成全局 rownum 再应用 OFFSET 的缺陷  
  • 此问题直接影响分页准确性,生产环境应规避该组合写法

Oracle与YashanDB的OFFSET分页执行计划对比:左侧为Oracle高效索引扫描,右侧为YashanDB低效全量排序


测试场景六:纯 OFFSET 分页查询(无 rownum)

测试语句

select object_id
from t1 where object_id is not null order by object_id desc
offset 10 rows fetch next 9 rows only;

Oracle 测试结果
耗时:0.00秒,IO:4 consistent gets
执行计划:WINDOW NOSORT STOPKEY + INDEX FULL SCAN DESCENDING,轻量高效。

YashanDB 测试结果
耗时:0.002秒,IO:2 db block gets
执行计划:INDEX RANGE SCAN DESCENDING + WINDOWLimit Expression 明确标注 (LIMIT: 9 OFFSET: 10),且 A-Rows = 9,证明 OFFSET/FETCH 本身已支持下推。

小结  

  • 单独使用 OFFSET/FETCH 时,YashanDB 表现优异,与 Oracle 基本持平  
  • 场景五的问题根源在于 rownum 的介入破坏了 OFFSET 的优化路径  
  • 验证结论:YashanDB 的 OFFSET/FETCH 原生支持良好,但与 rownum 混用存在兼容性风险

测试场景七:子查询 + OFFSET 分页

测试语句

select a.*,rownum rn from (
 select object_id
 from t1 where object_id is not null order by object_id desc
) a offset 10 rows fetch next 9 rows only;

Oracle 测试结果
耗时:0.00秒,IO:4 consistent gets
执行计划:WINDOW NOSORT STOPKEY + INDEX FULL SCAN DESCENDINGrowlimit_$$_rownumber 机制正常工作。

YashanDB 测试结果
耗时:0.004秒,IO:2 db block gets
执行计划:INDEX RANGE SCAN DESCENDING + WINDOWLimit Expression 正确解析,A-Rows = 9RN 值为 11~19,符合预期。

小结  

  • OFFSET/FETCH 置于子查询外部,YashanDB 可正确处理 rownum 并保证结果一致性  
  • 此写法是场景五问题的推荐替代方案:既保留 OFFSET 语义,又规避 rownum 冲突  
  • 实践建议:分页逻辑尽量解耦,避免在 OFFSET/FETCH 同一层混用 rownum

综合结论与选型建议

  1. YashanDB 23.5 的 Rownum/StopKey 下推能力成熟可靠,尤其在传统 rownum 嵌套分页(场景一至三)中优势明显,IO 与耗时全面优于 Oracle  
  2. 对标准 SQL:2008 OFFSET/FETCH 语法原生支持良好(场景六、七),但需注意避免与 rownum 同层混用(场景五)  
  3. 分析函数分页(ROW_NUMBER())仍是 Oracle 更优选择(场景四),YashanDB 当前版本尚未实现窗口函数的 STOPKEY 下推  
  4. 索引设计是分页性能的底层基石:YashanDB 索引包含 NULL 值的特性,在无谓词场景下天然适配,而 Oracle 需显式添加 IS NOT NULL 谓词才能启用索引  

如需深入探讨 数据库/中间件/技术栈 的性能调优实践,或了解 软件测试 中的 SQL 压测方法论,欢迎持续关注云栈社区的技术沉淀。




上一篇:从 OpenAI 收购 Astral,看 AI 公司如何争夺开发者工具链
下一篇:MySQL数据库三级模式结构解析与正确表述
您需要登录后才可以回帖 登录 | 立即注册

手机版|小黑屋|网站地图|云栈社区 ( 苏ICP备2022046150号-2 )

GMT+8, 2026-3-21 08:00 , Processed in 0.665148 second(s), 50 queries , Gzip On.

Powered by Discuz! X3.5

© 2025-2026 云栈社区.

快速回复 返回顶部 返回列表