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

ORACLE索引范围扫描逻辑读ARRAY

IT界数据库架构师的漂泊人生 2020-12-14
648

ORACLE数据库中索引范围扫描是非常常见的扫描方式。

一 创建表和数据

create table zfk select * from dba_objects;

-- Create table

create table ZFK

(

  owner          VARCHAR2(30),

  object_name    VARCHAR2(128),

  subobject_name VARCHAR2(30),

  object_id      NUMBER not null,

  data_object_id NUMBER,

  object_type    VARCHAR2(19),

  created        DATE,

  last_ddl_time  DATE,

  timestamp      VARCHAR2(19),

  status         VARCHAR2(7),

  temporary      VARCHAR2(1),

  generated      VARCHAR2(1),

  secondary      VARCHAR2(1),

  namespace      NUMBER,

  edition_name   VARCHAR2(30),

  cust_last_name VARCHAR2(30)

) pctfree 10


二创建唯一索引

-- Create/Recreate primary, unique and foreign key constraints 

alter table ZFK  add constraint ZFK_PK_OBJID primary key (OBJECT_ID) pctfree 10 using index ;


三检查信息

1 对象ID

select object_name,object_id,data_object_id from dba_objects where owner=user and  object_name in ('ZFK','ZFK_PK_OBJID'); 


OBJECT_NAME  OBJECT_ID DATA_OBJECT_ID

ZFK                                    119734 120052

ZFK_PK_OBJID           120051 120053


OBJECT_ID       十六进制

119734=>1D3B6

120051=>1D4F3

DATA_OBJECT_ID

120052=>1D4F4

120053=>1D4F5

在SQLPLUS中默认设置下运行下面的语句

select object_id,object_name,object_type from DBA_MONITER.zfk where   object_id between 1 and 900;

执行计划

----------------------------------------------------------

Plan hash value: 1077372689

--------------------------------------------------------------------------------------------

| Id  | Operation    | Name   | Rows  | Bytes | Cost (%CPU)| Time   |

--------------------------------------------------------------------------------------------

|   0 | SELECT STATEMENT    |   |   659 | 25701 | 15   (0)| 00:00:01 |

|   1 |  TABLE ACCESS BY INDEX ROWID| ZFK   |   659 | 25701 | 15   (0)| 00:00:01 |

|*  2 |   INDEX RANGE SCAN    | ZFK_PK_OBJID |   659 |   | 3   (0)| 00:00:01 |

--------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):

---------------------------------------------------

   2 - access("OBJECT_ID">=1 AND "OBJECT_ID"<=900)

统计信息

----------------------------------------------------------

 0  recursive calls

 0  db block gets

52  consistent gets

 0  physical reads

 0  redo size

      29485  bytes sent via SQL*Net to client

707  bytes received via SQL*Net from client

19  SQL*Net roundtrips to/from client

 0  sorts (memory)

 0  sorts (disk)

883  rows processed


从上面返回信息当中,我们得知返回883行数据,52次逻辑读,发送了29.485KB字节去客户端,来回反复19次网络传输。

SQL> show array 

arraysize 50

默认情况下是每50条发送一次给客户端。也就是说50条数据装车发货!

883/50=17次 


使用SYS用户使用ORADEBUG工具10200来跟踪逻辑读

SQL> oradebug setmypid;

已处理的语句

SQL> oradebug event 10200 trace name context forever,level 1;

已处理的语句

SQL> select object_id,object_name,object_type from DBA_MONITER.zfk where   object_id between 1 and 900;

已用时间:  00: 00: 00.14

SQL> oradebug event 10200 trace name context off;

已处理的语句

SQL> oradebug tracefile_name;

/u01/app/oracle/diag/rdbms/orcl/orcl/trace/orcl_ora_38712.trc


下面统计下读块操作的次数, 你看得出0x0001d4f5是叶块,0x0001d4f4是数据块

[oracle@svr3 trace]cat u01/app/oracle/diag/rdbms/orcl/orcl/trace/orcl_ora_38712.trc |grep "started for block"

ktrgtc2(): started for block <0x0004 : 0x0100021b> objd: 0x0001d4f5

ktrget2(): started for block  <0x0004 : 0x0100021c> objd: 0x0001d4f5

ktrget2(): started for block  <0x000d : 0x0300014b> objd: 0x0001d4f4

ktrget2(): started for block  <0x0004 : 0x0100021c> objd: 0x0001d4f5

ktrget2(): started for block  <0x000d : 0x0300014b> objd: 0x0001d4f4

ktrget2(): started for block  <0x0004 : 0x0100021c> objd: 0x0001d4f5

ktrget2(): started for block  <0x000d : 0x0300014b> objd: 0x0001d4f4

ktrget2(): started for block  <0x000d : 0x0300014c> objd: 0x0001d4f4

ktrget2(): started for block  <0x0004 : 0x0100021c> objd: 0x0001d4f5

ktrget2(): started for block  <0x000d : 0x0300014c> objd: 0x0001d4f4

ktrget2(): started for block  <0x0004 : 0x0100021c> objd: 0x0001d4f5

ktrget2(): started for block  <0x000d : 0x0300014c> objd: 0x0001d4f4

ktrget2(): started for block  <0x000d : 0x0300014d> objd: 0x0001d4f4

ktrget2(): started for block  <0x0004 : 0x0100021c> objd: 0x0001d4f5

ktrget2(): started for block  <0x000d : 0x0300014d> objd: 0x0001d4f4

ktrget2(): started for block  <0x0004 : 0x0100021c> objd: 0x0001d4f5

ktrget2(): started for block  <0x000d : 0x0300014e> objd: 0x0001d4f4

ktrget2(): started for block  <0x0004 : 0x0100021c> objd: 0x0001d4f5

ktrget2(): started for block  <0x000d : 0x0300014e> objd: 0x0001d4f4

ktrget2(): started for block  <0x000d : 0x0300014f> objd: 0x0001d4f4

ktrget2(): started for block  <0x0004 : 0x0100021c> objd: 0x0001d4f5

ktrget2(): started for block  <0x000d : 0x0300014f> objd: 0x0001d4f4

ktrget2(): started for block  <0x0004 : 0x0100021c> objd: 0x0001d4f5

ktrget2(): started for block  <0x000d : 0x0300014f> objd: 0x0001d4f4

ktrget2(): started for block  <0x000d : 0x03000150> objd: 0x0001d4f4

ktrget2(): started for block  <0x0004 : 0x0100021c> objd: 0x0001d4f5

ktrget2(): started for block  <0x000d : 0x03000150> objd: 0x0001d4f4

ktrget2(): started for block  <0x000d : 0x03000151> objd: 0x0001d4f4

ktrget2(): started for block  <0x0004 : 0x0100021c> objd: 0x0001d4f5

ktrget2(): started for block  <0x000d : 0x03000151> objd: 0x0001d4f4

ktrget2(): started for block  <0x0004 : 0x0100021d> objd: 0x0001d4f5

ktrget2(): started for block  <0x0004 : 0x0100021d> objd: 0x0001d4f5

ktrget2(): started for block  <0x000d : 0x03000151> objd: 0x0001d4f4

ktrget2(): started for block  <0x000d : 0x03000152> objd: 0x0001d4f4

ktrget2(): started for block  <0x0004 : 0x0100021d> objd: 0x0001d4f5

ktrget2(): started for block  <0x000d : 0x03000152> objd: 0x0001d4f4

ktrget2(): started for block  <0x000d : 0x03000153> objd: 0x0001d4f4

ktrget2(): started for block  <0x0004 : 0x0100021d> objd: 0x0001d4f5

ktrget2(): started for block  <0x000d : 0x03000153> objd: 0x0001d4f4

ktrget2(): started for block  <0x0004 : 0x0100021d> objd: 0x0001d4f5

ktrget2(): started for block  <0x000d : 0x03000153> objd: 0x0001d4f4

ktrget2(): started for block  <0x000d : 0x03000154> objd: 0x0001d4f4

ktrget2(): started for block  <0x0004 : 0x0100021d> objd: 0x0001d4f5

ktrget2(): started for block  <0x000d : 0x03000154> objd: 0x0001d4f4

ktrget2(): started for block  <0x000d : 0x03000155> objd: 0x0001d4f4

ktrget2(): started for block  <0x0004 : 0x0100021d> objd: 0x0001d4f5

ktrget2(): started for block  <0x000d : 0x03000155> objd: 0x0001d4f4

ktrget2(): started for block  <0x0004 : 0x0100021d> objd: 0x0001d4f5

ktrget2(): started for block  <0x000d : 0x03000155> objd: 0x0001d4f4

ktrget2(): started for block  <0x000d : 0x03000156> objd: 0x0001d4f4

ktrget2(): started for block  <0x000d : 0x03000155> objd: 0x0001d4f4

ktrget2(): started for block  <0x000d : 0x03000156> objd: 0x0001d4f4


然后把array值设置成1000

SQL> set array 1000

再运行跟踪,最好是退出重进SQLPLUS

oracle@svr3 trace]cat u01/app/oracle/diag/rdbms/orcl/orcl/trace/orcl_ora_38728.trc |grep "started for block"

ktrgtc2(): started for block <0x0004 : 0x0100021b> objd: 0x0001d4f5

ktrget2(): started for block  <0x0004 : 0x0100021c> objd: 0x0001d4f5

ktrget2(): started for block  <0x000d : 0x0300014b> objd: 0x0001d4f4

ktrget2(): started for block  <0x0004 : 0x0100021c> objd: 0x0001d4f5

ktrget2(): started for block  <0x000d : 0x0300014b> objd: 0x0001d4f4

ktrget2(): started for block  <0x000d : 0x0300014c> objd: 0x0001d4f4

ktrget2(): started for block  <0x000d : 0x0300014d> objd: 0x0001d4f4

ktrget2(): started for block  <0x000d : 0x0300014e> objd: 0x0001d4f4

ktrget2(): started for block  <0x000d : 0x0300014f> objd: 0x0001d4f4

ktrget2(): started for block  <0x000d : 0x03000150> objd: 0x0001d4f4

ktrget2(): started for block  <0x000d : 0x03000151> objd: 0x0001d4f4

ktrget2(): started for block  <0x0004 : 0x0100021d> objd: 0x0001d4f5

ktrget2(): started for block  <0x000d : 0x03000152> objd: 0x0001d4f4

ktrget2(): started for block  <0x000d : 0x03000153> objd: 0x0001d4f4

ktrget2(): started for block  <0x000d : 0x03000154> objd: 0x0001d4f4

ktrget2(): started for block  <0x000d : 0x03000155> objd: 0x0001d4f4

ktrget2(): started for block  <0x000d : 0x03000156> objd: 0x0001d4f4

ktrget2(): started for block  <0x000d : 0x03000155> objd: 0x0001d4f4

ktrget2(): started for block  <0x000d : 0x03000156> objd: 0x0001d4f4

发现读块次数少了很多!!


执行计划

统计信息

----------------------------------------------------------

 0  recursive calls

 0  db block gets

19  consistent gets

 0  physical reads

 0  redo size

      26374  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)

883  rows processed

只有19次逻辑读,2次装货发车,


总结:

1 索引范围扫描方式 是先根节点块=>叶节点块=>表数据块=>叶节点块.....

2 SQLPLUS ARRAY的值 极大地影响了回表次数

3 JAVA语言 如下设置stmt.setFetchSize(100);

4 范围扫描是单块读取,可以从等待事件上可知

5 太多的逻辑读次数会消耗很多CPU的时间.



文章转载自IT界数据库架构师的漂泊人生,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论