暂无图片
暂无图片
3
暂无图片
暂无图片
暂无图片

20260107_yashandb 分页查询深入解析

内容概述

数据库分页查询功能是处理大量数据时常用的技术,将结果集分成多个“页”返回,提高系统性能和用户体验。以下是关键要点: 1. 性能优化:避免一次性加载全部数据,减少内存消耗和网络传输 2. 提升响应速度:快速返回首屏数据 3. 改善用户体验:支持逐页浏览大数据集 4. 未分页的结果集一般比较大 5. 页码小的查询快,随着页码的增大,会越来越慢 YashanDb 23.5对于分页查询场景的优化 Rownum/StopKey的下推,本文使用Oracle 19C进行对比测试。

image-20260107121119838

测试结果总结

image-20260107192858979

测试场景一:无谓词分页查询(yashandb性能较优) 1. 场景一、无谓词分页查询性能对比: Oracle使用 TABLE ACCESS FULL, IO:172694 consistent gets,耗时:3.05秒 yashandb使用 INDEX FULL SCAN DESCENDING IO:2 db block gets , 耗时:0.020, 2. 由于Oracle数据库中索引不存储NULL值,而yashan数据库中索引包含表的索引列的所有数据(包括NULL),所以Oracle使用TABLE ACCESS FULL而yashan使用INDEX FULL SCAN DESCENDING。 说明:无谓词的分布查询,yashandb性能较好,但由于Oracle索引不存储NULL值,所以该场景对Oracle显不公平,咱们添加谓词后,在场景二有谓词分页查询,继续测试。 测试场景二:有谓词分页查询(yashandb性能较优) 1. 场景二:有谓词分页查询性能对比: Oracle 使用 INDEX FULL SCAN DESCENDING, IO:20913 consistent gets, 耗时:3.16秒 yashandb使用 INDEX FULL SCAN DESCENDING, IO:2 db block gets , 耗时:0.003, 2. YashanDb 23.5对于分页查询场景的优化 Rownum/StopKey的下推,yashandb的性能更优 说明:场景二、有谓词分页查询中yashan表现较优,但这个SQL写法存在性能问题,我们优化该SQL后,场景三、三层分页查询,继续测试。 测试场景三:三层分页查询(yashandb/oracle性能相当) 1. 场景三:三层分页查询性能对比: Oracle 使用 INDEX FULL SCAN DESCENDING, IO:4 consistent gets, 耗时:0.01秒 yashandb使用 INDEX FULL SCAN DESCENDING, IO:2 db block gets , 耗时:0.006秒, 2. 场景三、三层分页查询,oracle和yashandb 执行计划中都使用COUNT STOPKEY即Rownum/StopKey的下推,所以性能都不错。 说明:所以场景一和场景二中,Oracle性能表现不佳,是由于sql编写不规范造成的,下面我们使用分析函数实现分布查询。 测试场景四:分析函数分页查询(oracle性能较优) 1. 场景四、分析函数分页查询性能对比: Oracle 使用 WINDOW NOSORT STOPKEY, IO:4 consistent gets, 耗时:0.01秒 yashandb使用 WINDOW NOSORT(StopKey), IO:17576 db block gets, 耗时:3.182秒, 2. yashandb 第三步 3 - StopKey: 19, 有Operation Information,但这个步骤前面没有"*"号 3. yashandb 比Oracle多了步骤二 |* 2 | RESULT 测试场景五:offset 分页查询(oracle性能较优) 1. 场景五性能对比: Oracle使用 index full scan descending,IO:4 consistent gets,耗时:0.01秒 yashandb使用 index range scan , IO:17576 db block gets,耗时:7.065 2. 相同的sql语句,yashandb与Oracle 结果显示不一致 3. 怀疑yashandb的执行计划受rownum影响 测试场景六:offset 分页查询2(yashandb/oracle性能相当) 1. 场景六性能对比: Oracle使用 index full scan descending, IO:4 consistent gets,耗时:0.01秒 yashandb使用 INDEX RANGE SCAN DESCENDING,IO:2 db block gets,耗时:0.002秒 2. 通过场景六验证了,场景五中 yashandb与oracle 的rownum实现方法存在差异 测试场景七:offset 分页查询3(yashandb/oracle性能相当) 1. 场景七性能对比: Oracle使用 INDEX FULL SCAN DESCENDING, IO:4 consistent gets,耗时:0.01秒 yashandb使用 INDEX RANGE SCAN DESCENDING,IO:2 db block gets, 耗时:0.004秒 2. yashandb使用场景五、offset分页查询时,多一层记录rownum可以实现与Oracle相同的结果及性能。

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

测试语句

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测试结果

SQL> 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; OBJECT_ID RN ---------- ---------- 73112 11 73111 12 73110 13 73109 14 73108 15 73107 16 73106 17 73105 18 73104 19 9 rows selected. Elapsed: 00:00:03.05 Execution Plan ---------------------------------------------------------- Plan hash value: 2211185287 -------------------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes |TempSpc| Cost (%CPU)| Time | -------------------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 10M| 247M| | 77342 (1)| 00:00:04 | |* 1 | VIEW | | 10M| 247M| | 77342 (1)| 00:00:04 | | 2 | COUNT | | | | | | | | 3 | VIEW | | 10M| 123M| | 77342 (1)| 00:00:04 | | 4 | SORT ORDER BY | | 10M| 38M| 114M| 77342 (1)| 00:00:04 | | 5 | TABLE ACCESS FULL| T1 | 10M| 38M| | 48733 (1)| 00:00:02 | -------------------------------------------------------------------------------------- Predicate Information (identified by operation id): --------------------------------------------------- 1 - filter("RN"<20 AND "RN">10) Statistics ---------------------------------------------------------- 115 recursive calls 4 db block gets 172694 consistent gets 14654 physical reads 0 redo size 778 bytes sent via SQL*Net to client 492 bytes received via SQL*Net from client 2 SQL*Net roundtrips to/from client 0 sorts (memory) 1 sorts (disk) 9 rows processed SQL>

yashandb测试结果

SQL> 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; OBJECT_ID RN ----------- --------------------- 73112 11 73111 12 73110 13 73109 14 73108 15 73107 16 73106 17 73105 18 73104 19 Execution Plan ---------------------------------------------------------------- SQL hash value: 2900712025 Optimizer: ADOPT_C +----+--------------------------------+----------------------+------------+----------+----------+-------------+----------+----------+----------+----------+--------------------------------+ | Id | Operation type | Name | Owner | E - Rows | A - Rows | Cost(%CPU) | A - Time | Loops | Memory | Disk | Partition info | +----+--------------------------------+----------------------+------------+----------+----------+-------------+----------+----------+----------+----------+--------------------------------+ | 0 | SELECT STATEMENT | | | | 9| | 23| 10| 0| 0| | |* 1 | VIEW | | | 10000000| 9| 2803( 0)| 22| 10| 0| 0| | |* 2 | COUNT STOPKEY | | | 10000000| 19| 2803( 0)| 14| 20| 0| 0| | | 3 | VIEW | | | 10000000| 19| 1919( 0)| 12| 19| 0| 0| | | 4 | INDEX FULL SCAN DESCENDING | IDX_T1_OBJECTID | YASTEST | 10000000| 19| 1919( 0)| 10| 19| 0| 0| | +----+--------------------------------+----------------------+------------+----------+----------+-------------+----------+----------+----------+----------+--------------------------------+ Operation Information (identified by operation id): --------------------------------------------------- 1 - Predicate : filter(ROWNUM[OPTMZ-2] > 10[OPTMZ-0]) 2 - Predicate : filter(ROWNUM[OPTMZ-0] < 20[OPTMZ-0]) Statistics ---------------------------------------------------------------------------------------------------- 0 physical reads 2 db block gets 0 consistent gets 0 redo size 0 recursive calls 0 bytes sent via SQL*Net to client 0 bytes received via SQL*Net from client 0 SQL*Net roundtrips to/from client 0 sorts (memory) 0 sorts (disk) 9 rows processed 0 bytes sent via PX 0 block received 40 rows fetched. Elapsed: 00:00:00.020 SQL>

image-20251201114150924

小结

测试场景一:无谓词分页查询(yashandb性能较优) 1. 场景一、无谓词分页查询性能对比: Oracle使用 TABLE ACCESS FULL, IO:172694 consistent gets,耗时:3.05秒 yashandb使用 INDEX FULL SCAN DESCENDING IO:2 db block gets , 耗时:0.020秒, 2. 由于Oracle数据库中索引不存储NULL值,而yashan数据库中索引包含表的索引列的所有数据(包括NULL),所以Oracle使用TABLE ACCESS FULL而yashan使用INDEX FULL SCAN DESCENDING。 说明:无谓词的分布查询,yashandb性能较好,但由于Oracle索引不存储NULL值,所以该场景对Oracle显不公平,咱们添加谓词后,在场景二有谓词分页查询,继续测试。

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

测试语句

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测试结果

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 ) 5 a) where rn > 10 and rn < 20; OBJECT_ID RN ---------- ---------- 73111 11 73110 12 73109 13 73108 14 73107 15 73106 16 73105 17 73104 18 73103 19 9 rows selected. Elapsed: 00:00:03.16 Execution Plan ---------------------------------------------------------- Plan hash value: 462672863 ------------------------------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | ------------------------------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 9999K| 247M| 20970 (1)| 00:00:01 | |* 1 | VIEW | | 9999K| 247M| 20970 (1)| 00:00:01 | | 2 | COUNT | | | | | | | 3 | VIEW | | 9999K| 123M| 20970 (1)| 00:00:01 | |* 4 | INDEX FULL SCAN DESCENDING| IDX_T1_OBJECTID | 9999K| 38M| 20970 (1)| 00:00:01 | ------------------------------------------------------------------------------------------------- Predicate Information (identified by operation id): --------------------------------------------------- 1 - filter("RN"<20 AND "RN">10) 4 - filter("OBJECT_ID" IS NOT NULL) Statistics ---------------------------------------------------------- 1 recursive calls 0 db block gets 20913 consistent gets 0 physical reads 0 redo size 778 bytes sent via SQL*Net to client 520 bytes received via SQL*Net from client 2 SQL*Net roundtrips to/from client 0 sorts (memory) 0 sorts (disk) 9 rows processed SQL>

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 ) 5 a) where rn > 10 and rn < 20; OBJECT_ID RN ----------- --------------------- 73111 11 73110 12 73109 13 73108 14 73107 15 73106 16 73105 17 73104 18 73103 19 Execution Plan ---------------------------------------------------------------- SQL hash value: 460267372 Optimizer: ADOPT_C +----+--------------------------------+----------------------+------------+----------+----------+-------------+----------+----------+----------+----------+--------------------------------+ | Id | Operation type | Name | Owner | E - Rows | A - Rows | Cost(%CPU) | A - Time | Loops | Memory | Disk | Partition info | +----+--------------------------------+----------------------+------------+----------+----------+-------------+----------+----------+----------+----------+--------------------------------+ | 0 | SELECT STATEMENT | | | | 9| | 65| 10| 0| 0| | |* 1 | VIEW | | | 9999999| 9| 2803( 0)| 64| 10| 0| 0| | |* 2 | COUNT STOPKEY | | | 9999999| 19| 2803( 0)| 58| 20| 0| 0| | | 3 | VIEW | | | 9999999| 19| 1919( 0)| 53| 19| 0| 0| | |* 4 | INDEX RANGE SCAN DESCENDING| IDX_T1_OBJECTID | YASTEST | 9999999| 19| 1919( 0)| 37| 19| 0| 0| | +----+--------------------------------+----------------------+------------+----------+----------+-------------+----------+----------+----------+----------+--------------------------------+ Operation Information (identified by operation id): --------------------------------------------------- 1 - Predicate : filter(ROWNUM[OPTMZ-2] > 10[OPTMZ-0]) 2 - Predicate : filter(ROWNUM[OPTMZ-0] < 20[OPTMZ-0]) 4 - Predicate : access("T1"."OBJECT_ID" IS NOT NULL) Statistics ---------------------------------------------------------------------------------------------------- 0 physical reads 2 db block gets 0 consistent gets 0 redo size 0 recursive calls 0 bytes sent via SQL*Net to client 0 bytes received via SQL*Net from client 0 SQL*Net roundtrips to/from client 0 sorts (memory) 0 sorts (disk) 9 rows processed 0 bytes sent via PX 0 block received 41 rows fetched. Elapsed: 00:00:00.003 SQL>

小结

测试场景二:有谓词分页查询(yashandb性能较优) 1. 场景一、无谓词分页查询性能对比: Oracle 使用 INDEX FULL SCAN DESCENDING, IO:20913 consistent gets,耗时:3.16秒 yashandb使用 INDEX FULL SCAN DESCENDING, IO:2 db block gets , 耗时:0.003, 2. YashanDb 23.5对于分页查询场景的优化 Rownum/StopKey的下推,yashandb的性能更优 说明:场景二、有谓词分页查询中yashan表现较优,但这个SQL写法存在性能问题,我们优化该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测试结果

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 5 ) where rn > 10 ; OBJECT_ID RN ---------- ---------- 73111 11 73110 12 73109 13 73108 14 73107 15 73106 16 73105 17 73104 18 73103 19 9 rows selected. Elapsed: 00:00:00.00 Execution Plan ---------------------------------------------------------- Plan hash value: 1566820405 ------------------------------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | ------------------------------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 19 | 494 | 3 (0)| 00:00:01 | |* 1 | VIEW | | 19 | 494 | 3 (0)| 00:00:01 | |* 2 | COUNT STOPKEY | | | | | | | 3 | VIEW | | 19 | 247 | 3 (0)| 00:00:01 | |* 4 | INDEX FULL SCAN DESCENDING| IDX_T1_OBJECTID | 9999K| 38M| 3 (0)| 00:00:01 | ------------------------------------------------------------------------------------------------- Predicate Information (identified by operation id): --------------------------------------------------- 1 - filter("RN">10) 2 - filter(ROWNUM<20) 4 - filter("OBJECT_ID" IS NOT NULL) Statistics ---------------------------------------------------------- 0 recursive calls 0 db block gets 4 consistent gets 0 physical reads 0 redo size 778 bytes sent via SQL*Net to client 527 bytes received via SQL*Net from client 2 SQL*Net roundtrips to/from client 0 sorts (memory) 0 sorts (disk) 9 rows processed SQL>

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 5 ) where rn > 10 ; OBJECT_ID RN ----------- --------------------- 73111 11 73110 12 73109 13 73108 14 73107 15 73106 16 73105 17 73104 18 73103 19 Execution Plan ---------------------------------------------------------------- SQL hash value: 904852421 Optimizer: ADOPT_C +----+--------------------------------+----------------------+------------+----------+----------+-------------+----------+----------+----------+----------+--------------------------------+ | Id | Operation type | Name | Owner | E - Rows | A - Rows | Cost(%CPU) | A - Time | Loops | Memory | Disk | Partition info | +----+--------------------------------+----------------------+------------+----------+----------+-------------+----------+----------+----------+----------+--------------------------------+ | 0 | SELECT STATEMENT | | | | 9| | 27| 10| 0| 0| | |* 1 | VIEW | | | 19| 9| 884( 0)| 27| 10| 0| 0| | |* 2 | COUNT STOPKEY | | | 19| 19| 884( 0)| 23| 20| 0| 0| | | 3 | VIEW | | | 19| 19| 1( 0)| 21| 19| 0| 0| | |* 4 | INDEX RANGE SCAN DESCENDING| IDX_T1_OBJECTID | YASTEST | 19| 19| 1( 0)| 17| 19| 0| 0| | +----+--------------------------------+----------------------+------------+----------+----------+-------------+----------+----------+----------+----------+--------------------------------+ Operation Information (identified by operation id): --------------------------------------------------- 1 - Predicate : filter(ROWNUM[OPTMZ-2] > 10[OPTMZ-0]) 2 - Predicate : filter(ROWNUM[OPTMZ-0] < 20[OPTMZ-0]) 4 - Predicate : access("T1"."OBJECT_ID" IS NOT NULL) Statistics ---------------------------------------------------------------------------------------------------- 0 physical reads 2 db block gets 0 consistent gets 0 redo size 0 recursive calls 0 bytes sent via SQL*Net to client 0 bytes received via SQL*Net from client 0 SQL*Net roundtrips to/from client 0 sorts (memory) 0 sorts (disk) 9 rows processed 0 bytes sent via PX 0 block received 41 rows fetched. Elapsed: 00:00:00.006 SQL>

小结

测试场景三:三层分页查询(yashandb/oracle性能相当) 1. 场景一、无谓词分页查询性能对比: Oracle 使用 INDEX FULL SCAN DESCENDING, IO:4 consistent gets, 耗时:0.01秒 yashandb使用 INDEX FULL SCAN DESCENDING, IO:2 db block gets , 耗时:0.006秒, 2. 场景三、三层分页查询,oracle和yashandb 执行计划中都使用COUNT 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测试结果

SQL> select * from( select object_id,row_number() over (order by object_id desc) as rn from t1 where object_id is not null 4 ) where rn > 10 and rn < 20; OBJECT_ID RN ---------- ---------- 73111 11 73110 12 73109 13 73108 14 73107 15 73106 16 73105 17 73104 18 73103 19 9 rows selected. Elapsed: 00:00:00.01 Execution Plan ---------------------------------------------------------- Plan hash value: 617580278 ------------------------------------------------------------------------------------------------ | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | ------------------------------------------------------------------------------------------------ | 0 | SELECT STATEMENT | | 20 | 520 | 3 (0)| 00:00:01 | |* 1 | VIEW | | 20 | 520 | 3 (0)| 00:00:01 | |* 2 | WINDOW NOSORT STOPKEY | | 19 | 76 | 3 (0)| 00:00:01 | |* 3 | INDEX FULL SCAN DESCENDING| IDX_T1_OBJECTID | 9999K| 38M| 3 (0)| 00:00:01 | ------------------------------------------------------------------------------------------------ Predicate Information (identified by operation id): --------------------------------------------------- 1 - filter("RN">10 AND "RN"<20) 2 - filter(ROW_NUMBER() OVER ( ORDER BY INTERNAL_FUNCTION("OBJECT_ID") DESC )<20) 3 - filter("OBJECT_ID" IS NOT NULL) Statistics ---------------------------------------------------------- 1 recursive calls 0 db block gets 4 consistent gets 0 physical reads 0 redo size 778 bytes sent via SQL*Net to client 510 bytes received via SQL*Net from client 2 SQL*Net roundtrips to/from client 0 sorts (memory) 0 sorts (disk) 9 rows processed SQL>

yashandb测试结果

SQL> select * from( select object_id,row_number() over (order by object_id desc) as rn from t1 where object_id is not null 4 ) where rn > 10 and rn < 20; OBJECT_ID RN ----------- --------------------- 73111 11 73110 12 73109 13 73108 14 73107 15 73106 16 73105 17 73104 18 73103 19 Execution Plan ---------------------------------------------------------------- SQL hash value: 852340868 Optimizer: ADOPT_C +----+--------------------------------+----------------------+------------+----------+----------+-------------+----------+----------+----------+----------+--------------------------------+ | Id | Operation type | Name | Owner | E - Rows | A - Rows | Cost(%CPU) | A - Time | Loops | Memory | Disk | Partition info | +----+--------------------------------+----------------------+------------+----------+----------+-------------+----------+----------+----------+----------+--------------------------------+ | 0 | SELECT STATEMENT | | | | 9| | 3163398| 10| 0| 0| | | 1 | VIEW | | | 1895706| 9| 5445( 0)| 3163396| 10| 0| 0| | |* 2 | RESULT | | | 1895706| 9| 5445( 0)| 3163259| 10| 0| 0| | | 3 | WINDOW NOSORT | | | 9999999| 9999999| 3584( 0)| 2472263| 10000000| 0| 0| | |* 4 | INDEX RANGE SCAN DESCENDING| IDX_T1_OBJECTID | YASTEST | 9999999| 9999999| 1919( 0)| 678732| 10000000| 0| 0| | +----+--------------------------------+----------------------+------------+----------+----------+-------------+----------+----------+----------+----------+--------------------------------+ Operation Information (identified by operation id): --------------------------------------------------- 2 - Predicate : filter(ROW_NUMBER()[OPTMZ-2] < 20[OPTMZ-0] AND ROW_NUMBER()[OPTMZ-2] > 10[OPTMZ-0]) 3 - StopKey: 19 4 - Predicate : access("T1"."OBJECT_ID" IS NOT NULL) Statistics ---------------------------------------------------------------------------------------------------- 0 physical reads 17576 db block gets 0 consistent gets 0 redo size 0 recursive calls 0 bytes sent via SQL*Net to client 0 bytes received via SQL*Net from client 0 SQL*Net roundtrips to/from client 0 sorts (memory) 0 sorts (disk) 9 rows processed 0 bytes sent via PX 0 block received 41 rows fetched. Elapsed: 00:00:03.182 SQL>

小结

测试场景四:分析函数分页查询(yashandb/oracle性能相当) 1. 场景一、分析函数分页查询性能对比: Oracle 使用 WINDOW NOSORT STOPKEY, IO:4 consistent gets, 耗时:0.01秒 yashandb使用 WINDOW NOSORT(StopKey), IO:17576 db block gets, 耗时:3.182秒, 2. yashandb 第三步 3 - StopKey: 19, 有Operation Information,但这个步骤前面没有"*"号 3. yashandb 比Oracle多了步骤二 |* 2 | RESULT

测试场景五、offset 分页查询

测试语句

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测试结果

SQL> select object_id,rownum as rn from t1 where object_id is not null order by object_id desc 3 offset 10 rows fetch next 9 rows only; OBJECT_ID RN ---------- ---------- 73111 11 73110 12 73109 13 73108 14 73107 15 73106 16 73105 17 73104 18 73103 19 9 rows selected. Elapsed: 00:00:00.00 Execution Plan ---------------------------------------------------------- Plan hash value: 2445356698 ------------------------------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | ------------------------------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 19 | 988 | 20970 (1)| 00:00:01 | |* 1 | VIEW | | 19 | 988 | 20970 (1)| 00:00:01 | |* 2 | WINDOW NOSORT STOPKEY | | 9999K| 38M| 20970 (1)| 00:00:01 | | 3 | COUNT | | | | | | |* 4 | INDEX FULL SCAN DESCENDING| IDX_T1_OBJECTID | 9999K| 38M| 20970 (1)| 00:00:01 | ------------------------------------------------------------------------------------------------- Predicate Information (identified by operation id): --------------------------------------------------- 1 - filter("from$_subquery$_002"."rowlimit_$$_rownumber"<=19 AND "from$_subquery$_002"."rowlimit_$$_rownumber">10) 2 - filter(ROW_NUMBER() OVER ( ORDER BY INTERNAL_FUNCTION("OBJECT_ID") DESC )<=19) 4 - filter("OBJECT_ID" IS NOT NULL) Statistics ---------------------------------------------------------- 0 recursive calls 0 db block gets 4 consistent gets 0 physical reads 0 redo size 778 bytes sent via SQL*Net to client 489 bytes received via SQL*Net from client 2 SQL*Net roundtrips to/from client 0 sorts (memory) 0 sorts (disk) 9 rows processed SQL>

yashandb测试结果

SQL> select object_id,rownum as rn from t1 where object_id is not null order by object_id desc 3 offset 10 rows fetch next 9 rows only; OBJECT_ID RN ----------- --------------------- 73111 9999989 73110 9999988 73109 9999987 73108 9999986 73107 9999985 73106 9999984 73105 9999983 73104 9999982 73103 9999981 Execution Plan ---------------------------------------------------------------- SQL hash value: 2612163272 Optimizer: ADOPT_C +----+--------------------------------+----------------------+------------+----------+----------+-------------+----------+----------+----------+----------+--------------------------------+ | Id | Operation type | Name | Owner | E - Rows | A - Rows | Cost(%CPU) | A - Time | Loops | Memory | Disk | Partition info | +----+--------------------------------+----------------------+------------+----------+----------+-------------+----------+----------+----------+----------+--------------------------------+ | 0 | SELECT STATEMENT | | | | 9| | 7062241| 10| 0| 0| | | 1 | WINDOW | | | 9| 9| 7007( 0)| 7062033| 10| 0| 0| | | 2 | ORDER BY STOPKEY | | | 9999999| 20| 7007( 0)| 7062032| 20| 0| 0| | | 3 | COUNT | | | 9999999| 9999999| 2803( 0)| 1142157| 10000000| 0| 0| | |* 4 | INDEX RANGE SCAN | IDX_T1_OBJECTID | YASTEST | 9999999| 9999999| 1919( 0)| 612901| 10000000| 0| 0| | +----+--------------------------------+----------------------+------------+----------+----------+-------------+----------+----------+----------+----------+--------------------------------+ Operation Information (identified by operation id): --------------------------------------------------- 1 - Limit Expression: (LIMIT: 9[OPTMZ-0] OFFSET: 10[OPTMZ-0]) 2 - StopKey: 19[OPTMZ-0] 4 - Predicate : access("T1"."OBJECT_ID" IS NOT NULL) Statistics ---------------------------------------------------------------------------------------------------- 0 physical reads 17576 db block gets 0 consistent gets 0 redo size 0 recursive calls 0 bytes sent via SQL*Net to client 0 bytes received via SQL*Net from client 0 SQL*Net roundtrips to/from client 0 sorts (memory) 0 sorts (disk) 9 rows processed 0 bytes sent via PX 0 block received 41 rows fetched. Elapsed: 00:00:07.065 SQL>

小结

测试场景五:offset 分页查询(oracle性能较优) 1. 场景五性能对比: Oracle使用 index full scan descending,IO:4 consistent gets,耗时:0.01秒 yashandb使用 index range scan , IO:17576 db block gets,耗时:7.065 2. 相同的sql语句,yashandb与Oracle 结果显示不一致 3. 怀疑yashandb的执行计划受rownum影响

image-20260107161704838

测试场景六、offset 分页查询2

测试语句

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测试结果

SQL> select object_id from t1 where object_id is not null order by object_id desc 3 offset 10 rows fetch next 9 rows only; OBJECT_ID ---------- 73111 73110 73109 73108 73107 73106 73105 73104 73103 9 rows selected. Elapsed: 00:00:00.00 Execution Plan ---------------------------------------------------------- Plan hash value: 617580278 ------------------------------------------------------------------------------------------------ | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | ------------------------------------------------------------------------------------------------ | 0 | SELECT STATEMENT | | 19 | 741 | 3 (0)| 00:00:01 | |* 1 | VIEW | | 19 | 741 | 3 (0)| 00:00:01 | |* 2 | WINDOW NOSORT STOPKEY | | 19 | 76 | 3 (0)| 00:00:01 | |* 3 | INDEX FULL SCAN DESCENDING| IDX_T1_OBJECTID | 9999K| 38M| 3 (0)| 00:00:01 | ------------------------------------------------------------------------------------------------ Predicate Information (identified by operation id): --------------------------------------------------- 1 - filter("from$_subquery$_002"."rowlimit_$$_rownumber"<=19 AND "from$_subquery$_002"."rowlimit_$$_rownumber">10) 2 - filter(ROW_NUMBER() OVER ( ORDER BY INTERNAL_FUNCTION("OBJECT_ID") DESC )<=19) 3 - filter("OBJECT_ID" IS NOT NULL) Statistics ---------------------------------------------------------- 0 recursive calls 0 db block gets 4 consistent gets 0 physical reads 0 redo size 679 bytes sent via SQL*Net to client 476 bytes received via SQL*Net from client 2 SQL*Net roundtrips to/from client 0 sorts (memory) 0 sorts (disk) 9 rows processed SQL>

yashandb测试结果

SQL> select object_id from t1 where object_id is not null order by object_id desc 3 offset 10 rows fetch next 9 rows only; OBJECT_ID ----------- 73111 73110 73109 73108 73107 73106 73105 73104 73103 Execution Plan ---------------------------------------------------------------- SQL hash value: 1144927577 Optimizer: ADOPT_C +----+--------------------------------+----------------------+------------+----------+----------+-------------+----------+----------+----------+----------+--------------------------------+ | Id | Operation type | Name | Owner | E - Rows | A - Rows | Cost(%CPU) | A - Time | Loops | Memory | Disk | Partition info | +----+--------------------------------+----------------------+------------+----------+----------+-------------+----------+----------+----------+----------+--------------------------------+ | 0 | SELECT STATEMENT | | | | 9| | 17| 10| 0| 0| | | 1 | WINDOW | | | 9| 9| 1( 0)| 17| 10| 0| 0| | |* 2 | INDEX RANGE SCAN DESCENDING | IDX_T1_OBJECTID | YASTEST | 9| 20| 1( 0)| 14| 20| 0| 0| | +----+--------------------------------+----------------------+------------+----------+----------+-------------+----------+----------+----------+----------+--------------------------------+ Operation Information (identified by operation id): --------------------------------------------------- 1 - Limit Expression: (LIMIT: 9[OPTMZ-0] OFFSET: 10[OPTMZ-0]) 2 - Predicate : access("T1"."OBJECT_ID" IS NOT NULL) Statistics ---------------------------------------------------------------------------------------------------- 0 physical reads 2 db block gets 0 consistent gets 0 redo size 0 recursive calls 0 bytes sent via SQL*Net to client 0 bytes received via SQL*Net from client 0 SQL*Net roundtrips to/from client 0 sorts (memory) 0 sorts (disk) 9 rows processed 0 bytes sent via PX 0 block received 38 rows fetched. Elapsed: 00:00:00.002 SQL>

小结

测试场景六:offset 分页查询2(yashandb/oracle性能相当) 1. 场景六性能对比: Oracle使用 index full scan descending, IO:4 consistent gets,耗时:0.01秒 yashandb使用 INDEX RANGE SCAN DESCENDING,IO:2 db block gets,耗时:0.002秒 2. 通过场景六验证了,场景五中 yashandb与oracle 的rownum实现方法存在差异

测试场景七、offset 分页查询3

测试语句

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测试结果

SQL> select a.*,rownum rn from ( select object_id from t1 where object_id is not null order by object_id desc) a 4 offset 10 rows fetch next 9 rows only; OBJECT_ID RN ---------- ---------- 73111 11 73110 12 73109 13 73108 14 73107 15 73106 16 73105 17 73104 18 73103 19 9 rows selected. Elapsed: 00:00:00.00 Execution Plan ---------------------------------------------------------- Plan hash value: 3274483559 -------------------------------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | -------------------------------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 19 | 741 | 20970 (1)| 00:00:01 | |* 1 | VIEW | | 19 | 741 | 20970 (1)| 00:00:01 | |* 2 | WINDOW NOSORT STOPKEY | | 9999K| 123M| 20970 (1)| 00:00:01 | | 3 | COUNT | | | | | | | 4 | VIEW | | 9999K| 123M| 20970 (1)| 00:00:01 | |* 5 | INDEX FULL SCAN DESCENDING| IDX_T1_OBJECTID | 9999K| 38M| 20970 (1)| 00:00:01 | -------------------------------------------------------------------------------------------------- Predicate Information (identified by operation id): --------------------------------------------------- 1 - filter("from$_subquery$_003"."rowlimit_$$_rownumber"<=19 AND "from$_subquery$_003"."rowlimit_$$_rownumber">10) 2 - filter(ROW_NUMBER() OVER ( ORDER BY NULL )<=19) 5 - filter("OBJECT_ID" IS NOT NULL) Statistics ---------------------------------------------------------- 0 recursive calls 0 db block gets 4 consistent gets 0 physical reads 0 redo size 778 bytes sent via SQL*Net to client 507 bytes received via SQL*Net from client 2 SQL*Net roundtrips to/from client 0 sorts (memory) 0 sorts (disk) 9 rows processed SQL>

yashandb测试结果

SQL> select a.*,rownum rn from ( select object_id from t1 where object_id is not null order by object_id desc) a 4 offset 10 rows fetch next 9 rows only; OBJECT_ID RN ----------- --------------------- 73111 11 73110 12 73109 13 73108 14 73107 15 73106 16 73105 17 73104 18 73103 19 Execution Plan ---------------------------------------------------------------- SQL hash value: 79960360 Optimizer: ADOPT_C +----+--------------------------------+----------------------+------------+----------+----------+-------------+----------+----------+----------+----------+--------------------------------+ | Id | Operation type | Name | Owner | E - Rows | A - Rows | Cost(%CPU) | A - Time | Loops | Memory | Disk | Partition info | +----+--------------------------------+----------------------+------------+----------+----------+-------------+----------+----------+----------+----------+--------------------------------+ | 0 | SELECT STATEMENT | | | | 9| | 22| 10| 0| 0| | | 1 | WINDOW | | | 9| 9| 884( 0)| 18| 10| 0| 0| | | 2 | COUNT | | | 9| 20| 884( 0)| 16| 20| 0| 0| | | 3 | VIEW | | | 9| 20| 1( 0)| 14| 20| 0| 0| | |* 4 | INDEX RANGE SCAN DESCENDING| IDX_T1_OBJECTID | YASTEST | 9| 20| 1( 0)| 14| 20| 0| 0| | +----+--------------------------------+----------------------+------------+----------+----------+-------------+----------+----------+----------+----------+--------------------------------+ Operation Information (identified by operation id): --------------------------------------------------- 1 - Limit Expression: (LIMIT: 9[OPTMZ-0] OFFSET: 10[OPTMZ-0]) 4 - Predicate : access("T1"."OBJECT_ID" IS NOT NULL) Statistics ---------------------------------------------------------------------------------------------------- 0 physical reads 2 db block gets 0 consistent gets 0 redo size 0 recursive calls 0 bytes sent via SQL*Net to client 0 bytes received via SQL*Net from client 0 SQL*Net roundtrips to/from client 0 sorts (memory) 0 sorts (disk) 9 rows processed 0 bytes sent via PX 0 block received 40 rows fetched. Elapsed: 00:00:00.004 SQL>

小结

测试场景七:offset 分页查询3(yashandb/oracle性能相当) 1. 场景七性能对比: Oracle使用 INDEX FULL SCAN DESCENDING, IO:4 consistent gets,耗时:0.01秒 yashandb使用 INDEX RANGE SCAN DESCENDING,IO:2 db block gets, 耗时:0.004秒 2. yashandb使用场景五、offset分页查询时,多一层记录rownum可以实现与Oracle相同的结果及性能。
「喜欢这篇文章,您的关注和赞赏是给作者最好的鼓励」
关注作者
【版权声明】本文为墨天轮用户原创内容,转载时必须标注文章的来源(墨天轮),文章链接,文章作者等基本信息,否则作者和墨天轮有权追究责任。如果您发现墨天轮中有涉嫌抄袭或者侵权的内容,欢迎发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论