首页 > 数据库 >Oracle 分页的SQL语句优化

Oracle 分页的SQL语句优化

时间:2024-04-12 22:00:13浏览次数:16  
标签:语句 COUNT 00 mm SQL Oracle 100 null select

ORACLE的分页SQL,基本上在绝大部分的业务系统上都有这种SQL。处理这种SQL,基本上要用到两点:

(1). 利用rownum的COUNT STOPKEY特性.

(2). 利用索引的排序特性,消除sort order by .

 

今天,同事发给我两个SQL。

执行计划大概如下:

 

 第1个SQL的执行计划,没有出现COUNT STOPKEY,结合对应的SQL文本来看,分页框架就不对。 框架不对,就不可能出现COUNT STOPKEY,性能也就绝对的差。。

第2个SQL的执行计划,出现了SORT ORDER BY,进行了全表扫描,然后再排序,性能同样也会很差。

 

为了说明这个问题,做了简单测试。

1. 测试一张mm测试表。

create table mm as select * from dba_objects;
insert into mm select * from dba_objects;
commit;
insert into mm select * from dba_objects;
commit;
insert into mm select * from dba_objects;
commit;
insert into mm select * from dba_objects;
commit;
insert into mm select * from mm;
commit;
insert into mm select * from mm;
commit;
insert into mm select * from mm;
commit;

update mm set object_type='';
commit;

update mm set owner='';
commit;

 

 

 

 

 

 

 

 

 

 

2. 使用错误的分页框架,查看对应的执行计划。

set linesize 200
set pagesize 2000
alter session set statistics_level = all;
select count(0)
  from (select rownum rn, t.object_id
          from mm t
         where t.object_type is null
           and t.owner is null)
 where rn > 1
   and rn <=  100;

select * from table(dbms_xplan.display_cursor(null,null,'allstats alias outline LAST'));



------------------------------------------------------------------------------------------------
| Id  | Operation            | Name | Starts | E-Rows | A-Rows |   A-Time   | Buffers | Reads  |
------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT     |      |      1 |        |      1 |00:00:01.62 |   59480 |  59469 |
|   1 |  SORT AGGREGATE      |      |      1 |      1 |      1 |00:00:01.62 |   59480 |  59469 |
|*  2 |   VIEW               |      |      1 |   4758K|     99 |00:00:01.62 |   59480 |  59469 |
|   3 |    COUNT             |      |      1 |        |   4559K|00:00:00.94 |   59480 |  59469 |
|*  4 |     TABLE ACCESS FULL| MM   |      1 |   4758K|   4559K|00:00:00.55 |   59480 |  59469 |
------------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   2 - filter(("RN"<=100 AND "RN">1))
   4 - filter(("T"."OBJECT_TYPE" IS NULL AND "T"."OWNER" IS NULL))

 

 

 

 

 

 

 

 

 

 

 

 

 

 

使用了错误的分页框架后,无法利用COUNT STOPKEY特性,buffer读高达59480。

 

3. 使用正确的分页框架。

select count(0)
  from (select *
          from (select t.*, rownum rn
                  from (select t.object_id
                          from mm t
                         where t.object_type is null
                           and t.owner is null) t)
         where rownum <= 100)
 where rn > 1;

select * from table(dbms_xplan.display_cursor(null,null,'allstats alias outline LAST'));



Plan hash value: 1654568715

--------------------------------------------------------------------------------------------------
| Id  | Operation              | Name | Starts | E-Rows | A-Rows |   A-Time   | Buffers | Reads  |
--------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT       |      |      1 |        |      1 |00:00:00.03 |       5 |     13 |
|   1 |  SORT AGGREGATE        |      |      1 |      1 |      1 |00:00:00.03 |       5 |     13 |
|*  2 |   VIEW                 |      |      1 |    100 |     99 |00:00:00.03 |       5 |     13 |
|*  3 |    COUNT STOPKEY       |      |      1 |        |    100 |00:00:00.03 |       5 |     13 |
|   4 |     VIEW               |      |      1 |   4758K|    100 |00:00:00.02 |       5 |     13 |
|   5 |      COUNT             |      |      1 |        |    100 |00:00:00.02 |       5 |     13 |
|*  6 |       TABLE ACCESS FULL| MM   |      1 |   4758K|    100 |00:00:00.02 |       5 |     13 |
--------------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   2 - filter("RN">1)
   3 - filter(ROWNUM<=100)
   6 - filter(("T"."OBJECT_TYPE" IS NULL AND "T"."OWNER" IS NULL))

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

使用了正确的分页框架后,利用了COUNT STOPKEY特性,buffer读才13。

 

4. 第一种分页SQL,分页语句没有使用order by排序,但实际上我们常见的分页语句类似于第2种SQL,也即分页语句中带有order by。 这种情况下,仅仅利用COUNT STOPKEY特性,如果不消除order by,性能仍然不会太好。

select *
  from (select *
          from (select t.*, rownum rn
                  from (select t.object_id
                          from mm t
                         where t.object_type is null
                           and t.owner is null
                         order by data_object_id) t)
         where rownum <= 100)
 where rn > 1;

select * from table(dbms_xplan.display_cursor(null,null,'allstats alias outline LAST'));

-------------------------------------------------------------------------------------------------------------------------------------------------
| Id  | Operation               | Name | Starts | E-Rows | A-Rows |   A-Time   | Buffers | Reads  | Writes |  OMem |  1Mem | Used-Mem | Used-Tmp|
-------------------------------------------------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT        |      |      1 |        |     99 |00:00:01.80 |   59483 |  59497 |   7256 |       |       |          |         |
|*  1 |  VIEW                   |      |      1 |    100 |     99 |00:00:01.80 |   59483 |  59497 |   7256 |       |       |          |         |
|*  2 |   COUNT STOPKEY         |      |      1 |        |    100 |00:00:01.80 |   59483 |  59497 |   7256 |       |       |          |         |
|   3 |    VIEW                 |      |      1 |   4758K|    100 |00:00:01.80 |   59483 |  59497 |   7256 |       |       |          |         |
|   4 |     COUNT               |      |      1 |        |    100 |00:00:01.80 |   59483 |  59497 |   7256 |       |       |          |         |
|   5 |      VIEW               |      |      1 |   4758K|    100 |00:00:01.80 |   59483 |  59497 |   7256 |       |       |          |         |
|   6 |       SORT ORDER BY     |      |      1 |   4758K|    100 |00:00:01.80 |   59483 |  59497 |   7256 |    63M|  2776K|  100M (1)|   58368 |
|*  7 |        TABLE ACCESS FULL| MM   |      1 |   4758K|   4559K|00:00:00.76 |   59480 |  59469 |      0 |       |       |          |         |
-------------------------------------------------------------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   1 - filter("RN">1)
   2 - filter(ROWNUM<=100)
   7 - filter(("T"."OBJECT_TYPE" IS NULL AND "T"."OWNER" IS NULL))

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

5. 这时,我们需要利用索引已经排序的特性来消除sort order by . 针对这个SQL,我们可以创建如下索引:

create index idx_mm_01 on mm(data_object_id, object_type, owner, 0);

 

 

6. 创建完索引后,我们看新的执行计划。

select *
  from (select *
          from (select t.*, rownum rn
                  from (select t.object_id
                          from mm t
                         where t.object_type is null
                           and t.owner is null
                         order by data_object_id) t)
         where rownum <= 100)
 where rn > 1;

select * from table(dbms_xplan.display_cursor(null,null,'allstats alias outline LAST'));

--------------------------------------------------------------------------------------------------------
| Id  | Operation                        | Name      | Starts | E-Rows | A-Rows |   A-Time   | Buffers |
--------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT                 |           |      1 |        |     99 |00:00:00.01 |      43 |
|*  1 |  VIEW                            |           |      1 |    100 |     99 |00:00:00.01 |      43 |
|*  2 |   COUNT STOPKEY                  |           |      1 |        |    100 |00:00:00.01 |      43 |
|   3 |    VIEW                          |           |      1 |   4758K|    100 |00:00:00.01 |      43 |
|   4 |     COUNT                        |           |      1 |        |    100 |00:00:00.01 |      43 |
|   5 |      VIEW                        |           |      1 |   4758K|    100 |00:00:00.01 |      43 |
|   6 |       TABLE ACCESS BY INDEX ROWID| MM        |      1 |   4758K|    100 |00:00:00.01 |      43 |
|*  7 |        INDEX FULL SCAN           | IDX_MM_01 |      1 |  11897 |    100 |00:00:00.01 |      10 |
--------------------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   1 - filter("RN">1)
   2 - filter(ROWNUM<=100)
   7 - access("T"."OBJECT_TYPE" IS NULL AND "T"."OWNER" IS NULL)
       filter(("T"."OBJECT_TYPE" IS NULL AND "T"."OWNER" IS NULL))

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

利用了COUNT STOPKEY特性,同时利用了索引的已经排序的特性,buffer读才43。

 

标签:语句,COUNT,00,mm,SQL,Oracle,100,null,select
From: https://www.cnblogs.com/missyou-shiyh/p/18132207

相关文章

  • java代码审计-sqli
    Java代码审计-sqli0x01漏洞挖掘jdbc在上古时期,人们往往这么从数据库获取数据。publicUsergetUserById(Stringid)throwsSQLException{Connectionconnection=JDBCTOOLS.getConnection(); Stringsql="selectid,usernamefromuserwhereid="+id; State......
  • linux环境安装——mysql集群安装复习——主从复制
    1、首先安装mysql: mkdir-p/soft/mysql8mkdir-p/evir/mysql8执行上传文件操作rpm-qa|grepmariadb查询是否有这个文件rpm-e--nodepsmariadb-libs进行删除rpm-qa|grepmariadb查询这个文件是否删干净tar-xf/soft/my......
  • SQL SERVER 从入门到精通 第5版 第三篇 高级应用 第10章 存储过程 读书笔记
    第10章存储过程 >.存储过程概述存储过程(storedprocedure)是预编译SQL语句的集合,这些语句存储在一个名称下并作为一个单元来处理.存储过程取代了传统的逐条执行SQL语句的方式.一个存储过程中可以包含增删改查等一系列SQL语句,当这个存储过程被调用时,这些操作也......
  • oracle 更改schema名
    1、用sysdba账号登入数据库,然后查询到要更改的用户信息:SELECTuser#,nameFROMuser$;2、更改用户名并提交: updateuser$setname='demokygs'whereuser#=111;COMMIT;3、强制刷新:ALTERSYSTEMCHECKPOINT;ALTERSYSTEMFLUSHSHARED_POOL;4、更新用户的密码:......
  • 从Oracle迁移到PostgreSQL的十大理由
    从Oracle迁移到PostgreSQL的十大理由PostgreSQLChina官方微信:开源软件联盟PostgreSQL分会 19人赞同了该文章作者:保罗·纳穆格PaulNamuag能够担任各种职务,受益于在过去的18年中有机会使用各种技术。他从2005年开始担任图形艺术家和MS.Net开发人员......
  • Oracle VM VirtualBox网络设置
    首先说明vmWare功能比VirtualBox强大,网卡设置也更加灵活,并且可以一种模式搞定你所有的需求,如果能用vmWare那就就优先用vmWareVirtualBox的网络设置和vmWare的网络设置不同vmWare的NAT模式和hostOnly模式都会在宿主机中映射一个虚拟网卡,通过这个网卡宿主机可以通过IP地址链......
  • oracle数据库技术没落了吗
    oracle数据库技术没落了吗重庆思庄2023-05-1717:26重庆 随着新兴技术的不断涌现,一些人开始质疑传统的Oracle数据库技术是否已经过时,甚至已经走向没落。然而,在现实应用中,Oracle数据库技术仍然是最受欢迎的数据库之一。尽管其他技术比如云计算和大数据技术造成了......
  • 使用内置函数 (SQL Server) 验证、查询和更改 JSON 数据
    使用内置函数(SQLServer)验证、查询和更改JSON数据项目2023/09/0313个参与者反馈 本文内容此页上的示例JSON文本使用ISJSON函数验证JSON文本使用JSON_VALUE函数从JSON文本中提取值使用JSON_QUERY函数从JSON文本中提取对象或数组显示另外......
  • 为什么传统行业几乎都用Oracle,而互联网行业几乎都不用Oracle呢?
    为什么传统行业几乎都用Oracle,而互联网行业几乎都不用Oracle呢?17 赞同7 评论10 收藏先抛结论:对互联网企业来说可以用,但是没有必要。理由如下:1、oracle目前来说还是占据着主流。除了互联网之外的传统行业基本上还是用的oracle,无论从规模还是数量上,比sql有......
  • mysql-子查询的学习
    子查询由一个具体的需求,引入子查询谁的工资比Abel的高SELECT*fromemployeesWHEREsalary>(SELECTsalaryFROMemployeesWHERElast_name='Abel')--自连接SELECTe2.*......