实验环境如下:
SQL> select * from v$version; BANNER -------------------------------------------------------------------------------- Oracle Database 11g Enterprise Edition Release 11.2.0.4.0 - 64bit Production PL/SQL Release 11.2.0.4.0 - Production CORE 11.2.0.4.0 Production TNS for 64-bit Windows: Version 11.2.0.4.0 - Production NLSRTL Version 11.2.0.4.0 - Production
准备的测试表:
create table t(id integer,name varchar2(100)); insert into t select rownum * 2 -1 as id, lengthb(dbms_random.string('a',50)) as name from dual connect by level<=100; alter table t minimize records_per_block; insert into t select rownum * 2 as id, lengthb(dbms_random.string('a',50)) as name from dual connect by level<=100; select id,dbms_rowid.rowid_block_number(rowid) from t; commit; create index idx_t_id on t(id);
第一次插入100条记录放到块1, 第二次插入100条记录到块2。 两个块之间的ID记录是相间隔的,目的是为了下面走索引时候最大限度的增加逻辑读。
PS:minimize 命令的作用是设定该表的所有块的记录数不超过存量的块的记录数。
SQL> select /*+rule*/ * from t where id<300; 已选择200行。 执行计划 ---------------------------------------------------------- Plan hash value: 514881935 ------------------------------------------------ | Id | Operation | Name | ------------------------------------------------ | 0 | SELECT STATEMENT | | | 1 | TABLE ACCESS BY INDEX ROWID| T | |* 2 | INDEX RANGE SCAN | IDX_T_ID | ------------------------------------------------ Predicate Information (identified by operation id): --------------------------------------------------- 2 - access("ID"<300) Note ----- - rule based optimizer used (consider using cbo) 统计信息 ---------------------------------------------------------- 0 recursive calls 0 db block gets 215 consistent gets 0 physical reads 0 redo size 5350 bytes sent via SQL*Net to client 663 bytes received via SQL*Net from client 15 SQL*Net roundtrips to/from client 0 sorts (memory) 0 sorts (disk) 200 rows processed
这215次逻辑读,有200次是由访问T表的数据贡献的,剩余的15次是读取索引段的位图+访问索引段的块贡献的。
对比一下全表扫描的情况:
SQL> select * from t; 已选择200行。 执行计划 ---------------------------------------------------------- Plan hash value: 1601196873 -------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | -------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 200 | 13000 | 3 (0)| 00:00:01 | | 1 | TABLE ACCESS FULL| T | 200 | 13000 | 3 (0)| 00:00:01 | -------------------------------------------------------------------------- Note ----- - dynamic sampling used for this statement (level=2) 统计信息 ---------------------------------------------------------- 0 recursive calls 0 db block gets 21 consistent gets 0 physical reads 0 redo size 5350 bytes sent via SQL*Net to client 663 bytes received via SQL*Net from client 15 SQL*Net roundtrips to/from client 0 sorts (memory) 0 sorts (disk) 200 rows processed
全表扫描仅仅需要21次逻辑读,而索引访问却需要215次,远远高于前者。所以凡事无绝对,遇事要根据实际情况分析,实事求是。
PS: 全表扫描的这21次逻辑读,有约17次是读取表T的数据贡献的,虽然只有2个块有数据,但访问到高水位线+段头块,就已经有6个块了。
另外,这200条记录,每次载送15条(array size 参数决定的)后就返回一次给客户端,因此也会产生14次左右的逻辑读。
版权声明:本文为博主原创文章,未经博主允许不得转载。
全表扫描 索引 逻辑读