Oracle: count STOPKEY 优化

简介: Oracle数据库中select * from test where id> 1000 and rownum=1这样的语句应该怎样优化

     在Oracle数据库的日常运维中,经常发现这样一些语句,这些语句对一张大表(数据量由几百万行至几千万行)执行含有几个条件的查询,然后返回一行或者是几行,这些语句的最简单的形式像下面这个样子:

    select * from test where id< 1000 and rownum=1;

    这类语句在awr报告中也偶尔可以看到,它们的逻辑读非常大,返回的行数却不多。这种语句需要优化吗,需要怎么优化,怎么查看这类语句是否存在性能瓶颈。下面通过一个简单的例子说明这类语句怎么查看性能以及如何优化。首先第一步是创建一张测试表,使用下面的语句:

createtable model_tab as(select*from dual
    model 
      dimension by(0 d)      measures (0 rnum)      rules iterate(1000000)(rnum[ITERATION_NUMBER]= ITERATION_NUMBER+1));

   上面的语句使用的是select 的model语句,model语句定义了一个一维的立方体,这个数组的维度值是Oracle数据库dual表的d列,值是循环的次数加1,总共循环1000000次,创建表的数据是1000000行。

    运行下面的语句查询表,以rnum为条件查询一下这张表,语句如下:

select*from model_tab where rnum<=1000and rownum=1;

在没有索引的情况下,语句的执行计划如下:

PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------Plan hash value:2500570731--------------------------------------------------------------------------------| Id  | Operation          | Name      | Rows  | Bytes | Cost (%CPU)|Time|--------------------------------------------------------------------------------|0|SELECT STATEMENT   ||1|10|3(0)|00:00:01||*1|COUNT STOPKEY     |||||||*2|TABLE ACCESS FULL| MODEL_TAB |3|30|3(0)|00:00:01|--------------------------------------------------------------------------------Predicate Information (identified by operation id):PLAN_TABLE_OUTPUT
-----------------------------------------------------------------------------------------------------------------------------------1- filter(ROWNUM=1)2- filter("RNUM"<=1000)

        从上面的执行计划可以看出,这条语句执行了全表扫描,总共扫描了三行数据,使用了count stopkey操作。在model_tab表的rnum列上创建索引

create index idx_rnum on model_tab(rnum);

     索引创建后,再查看语句的执行计划,变成下面这个

--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------Plan hash value:2837899601--------------------------------------------------------------------------------------------------| Id  | Operation                            | Name      | Rows  | Bytes | Cost (%CPU)|Time|--------------------------------------------------------------------------------------------------|0|SELECT STATEMENT                     ||1|10|4(0)|00:00:01||*1|COUNT STOPKEY                       |||||||2|TABLE ACCESS BY INDEX ROWID BATCHED| MODEL_TAB |3|30|4(0)|00:00:01||*3|    INDEX RANGE SCAN                  | IDX_RNUM  |1000||3(0)|00:00:01|--------------------------------------------------------------------------------------------------PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------Predicate Information (identified by operation id):---------------------------------------------------1- filter(ROWNUM=1)3- access("RNUM"<=1000)

     优化器使用了刚才创建的索引,执行了范围扫描,扫描了1000行数据,可见Oracle优化器认为这个计划比原来的全表扫描性能更好,可是,比较这两个执行计划,从返回行数及成本来看,没有明显的差别,甚至使用索引的范围扫描扫描的行数更多。但是,Oracle优化器为什么会选择使用索引,这里优化的选择正确吗,看一下这条语句再有无索引的情况下实际执行的统计信息,没有索引的情况下,统计信息如下:

Statistics
----------------------------------------------------------0  recursive calls
0  db block gets
4  consistent gets
0  physical reads
0  redo size
621  bytes sent via SQL*Net to client
415  bytes received via SQL*Net from client
2  SQL*Net roundtrips to/from client
0  sorts (memory)0  sorts (disk)1  rows processed

创建索引后,统计信息如下:

0  recursive calls
0  db block gets
4  consistent gets
0  physical reads
0  redo size
623  bytes sent via SQL*Net to client
415  bytes received via SQL*Net from client
2  SQL*Net roundtrips to/from client
0  sorts (memory)0  sorts (disk)1  rows processed

     还是没有明显的差别,都是4个一致性读,难道有没有索引这条语句的执行效率相差无几,改一下语句里rnum的条件看一看

select*from model_tab where rnum>=100000and rownum=1;

  rnum的条件改成大于10万,再看一下有无索引情况下语句执行的状态统计,在没有索引的情况下:

Statistics
----------------------------------------------------------0  recursive calls
0  db block gets
208  consistent gets
0  physical reads
0  redo size
622  bytes sent via SQL*Net to client
417  bytes received via SQL*Net from client
2  SQL*Net roundtrips to/from client
0  sorts (memory)0  sorts (disk)1  rows processed

在有索引的情况下

Statistics
----------------------------------------------------------0  recursive calls
0  db block gets
4  consistent gets
0  physical reads
0  redo size
626  bytes sent via SQL*Net to client
417  bytes received via SQL*Net from client
2  SQL*Net roundtrips to/from client
0  sorts (memory)0  sorts (disk)1  rows processed

     从上面的语句执行的统计信息来看,在有索引的情况下,逻辑读(4个)明显少于无索引的情况下的逻辑读(208)个,有着明显的优势。

     从上面的比较来看,在没有索引,执行全表情况下,语句执行的效率和执行条件有关系,这时应为count stopkey操作时,在找到符合条件的数据时,就会停止全表扫描,返回数据,语句的执行效率有查找的条件有关系,也同数据分布有关系,执行效率播放较大。而在有索引的情况下,执行范围扫描,扫描到符合条件的数据后也会停止扫描,返回数据,则语句的执行效率相对稳定,这时由btree索引的性质决定的。如果在数据库的日常运维和awr报告中发现此类语句单词执行逻辑读较多或占用cpu时间过长,就要检查是否已经为此类语句建立有效的索引,因为如果执行的是范围索引,此类语句的逻辑读应该较小,尤其是在查询的条件有多个时,创建合适的符合索引更是十分必要,对语句的性能提高也更大,这时因为在多个条件下,很可能会在扫描完全表才能发现符合条件的数据。


相关文章
|
9天前
|
SQL Oracle 关系型数据库
Oracle数据库优化方法
【10月更文挑战第25天】Oracle数据库优化方法
20 7
|
9天前
|
存储 Oracle 关系型数据库
Oracle数据库优化策略
【10月更文挑战第25天】Oracle数据库优化策略
13 5
|
3月前
|
监控 Oracle 关系型数据库
"深度剖析:Oracle SGA大小调整策略——从组件解析到动态优化,打造高效数据库性能"
【8月更文挑战第9天】在Oracle数据库性能优化中,系统全局区(SGA)的大小调整至关重要。SGA作为一组共享内存区域,直接影响数据库处理能力和响应速度。本文通过问答形式介绍SGA调整策略:包括SGA的组成(如数据缓冲区、共享池等),如何根据负载与物理内存确定初始大小,手动调整SGA的方法(如使用`ALTER SYSTEM`命令),以及利用自动内存管理(AMM)特性实现智能调整。调整过程中需注意监控与测试,确保稳定性和性能。
267 2
|
5月前
|
SQL Oracle 关系型数据库
Oracle游标的使用和优化技巧
Oracle游标的使用和优化技巧
|
4月前
|
SQL Oracle 关系型数据库
Oracle游标的使用和优化技巧
Oracle游标的使用和优化技巧
|
4月前
|
SQL 存储 Oracle
Oracle数据库中游标的工作原理与优化方法
Oracle数据库中游标的工作原理与优化方法
|
6月前
|
存储 Oracle 数据管理
Oracle 12c的自动数据优化(ADO)与热图:数据管理的“瘦身”与“透视”艺术
【4月更文挑战第19天】Oracle 12c的ADO和热图技术革新数据管理。ADO智能清理无用数据,优化存储,提升查询速度,实现数据&quot;瘦身&quot;;热图则以直观的视觉表示展示数据分布和状态,助力识别性能瓶颈,犹如数据的&quot;透视&quot;工具。这两项技术结合,强化数据管理,为企业业务发展保驾护航。
|
SQL Oracle 关系型数据库
Oracle数据库优化的总结及优化方法
Oracle数据库优化的总结及优化方法
95 0
|
存储 SQL Oracle
Oracle优化避免索引失效
Oracle优化避免索引失效
357 0
|
SQL Oracle 关系型数据库
Oracle优化问题
Oracle优化问题