一、 先介绍一下oracle的SGA:数据库的系统全局区,SGA主要由三部分构成:共享池、数据缓冲区、日志缓冲区。
1、 共享池又由两部分构成:共享SQL区和数据字典缓冲区。共享SQL区专门存放用户SQL命令,oracle使用最近最少使用等优先级算法来更新覆盖;数据字典缓冲区(library cache)存放数据库运行的动态信息。数据库运行一段时间后,DBA需要查看这些内存区域的命中率以从数据库角度对数据库性能调优。通过执行下述语句查看:
select (sum(pins - reloads)) / sum(pins) "Lib Cache" from v$librarycache;
--查看共享SQL区的重用率,最好在90%以上,否则需要增加共享池的大小。
select (sum(gets - getmisses - usage - fixED)) / sum(gets) "Row Cache" from v$rowcache;
--查看数据字典缓冲区的命中率,最好在90%以上,否则需要增加共享池的大小。
2、 数据缓冲区:存放sql运行结果抓取到的data block;
SELECT name, value FROM v$sysstat WHERE name IN ('db block gets', 'consistent gets','physical reads');
-- 查看数据库数据缓冲区的使用情况。查询出来的结果可以计算出来数据缓冲区的使用命中率=1 - ( physical reads / (db block gets + consistent gets) )。命中率应该在90%以上,否则需要增加数据缓冲区的大小。
3、 日志缓冲区:存放数据库运行生成的日志。
select name,value from v$sysstat where name in ('redo entries','redo log space requests');
--查看日志缓冲区的使用情况。查询出的结果可以计算出日志缓冲区的申请失败率:申请失败率=requests/entries,申请失败率应该接近于0,否则说明日志缓冲区开设太小,需要增加ORACLE数据库的日志缓冲区。
二.Sql语句的执行步骤:
了解sql的执行步骤有利于更好的优化它们,每条sql语句执行时都要经历以下几步:
1. Create cursor ;
2. Parse, if it is not already in the shared pool.;
3. Any query in the statement is processed.
4. Bind Variables
5. Execute.
6. If possible, the statement is parallelized.
7. Rows to be returned are fetched.
其中,Parse—是最有优化潜力的阶段。
Cursor创建后,oracle将在share pool中寻找是否该sql语句已经存在,若已经存在且已经被parsed,则不需要再执行parse,直接到下一步。若未在share pool中找到,则parse步一般需要执行下面步骤:
1. The statement is validated.
2. The data is validated.
3. Locks are allocated.
4. Privileges are verified.
5. The execution plan is determined.
6. The statement is loaded into the shared SQL area.
--parse有这么多步骤,所以能利用sharepool中现成的parse结果很重要。
三. 如何提高share pool中Sql共享率?
要实现sql共享,跳过parse步骤,有如下基本要求条件:
1. sql文本完全相同:
--uppercase and lowercase
--white space (spaces, tabs, carriage returns)
--comments
2.参考对象相同:
--Referenced schema’s objects must be the same objects
3. 绑定变量相同
--Bind variables must match the same name and data type.(所以对于格式相同、具体条件不同的sql,建议经常使用变量来代替常量,以尽量使用重复sql代码,避开parse阶段,提高执行速度)
--tip:
--尽量使用存储过程;尽量使用变量代替常量,可以提高share pool共享率,跳过parse阶段,提高效率。
四.什么是好的sql语句?
总结出以下特征:
* 尽量使用 PL/SQL提高性能: PL/SQL可以将sql语句块一次送给数据库服务器处理,不用PL/SQL只能一句一句送。
* 尽量使用stored procedure:降低oracle通过网络传输的数据量,并能提高共享sql区域的重用率。
* 尽量使用packages: Packages在第一次调用时能将整个包 load进内存,对提高性能有帮助。
* 尽量使用cached sequences 来生成primary key :提高主键生成速度和使用性能。
* 很好地利用空间:如用VARCHAR2 数据类型代替 CHAR等
* 只在非常必要时才使用hint:仅在对sql的执行计划非常肯定地要使用hint时才使用。
五.Sql优化工具的介绍:
sqlexpert;toad;explain-table;PL/SQL;OEM等
掌握一种,熟练使用即可。
我的习惯:看执行计划用sqlplus 的autotrace,优化用sql expert。
--Autotrace使用方法:
1. DBA在db中创建plustrace 角色:运行@*/sqlplus/admin/plustrce.sql
2. DBA给用户赋予角色:grant plustrace to username;
3. 用户创建自己的plan_table:运行@*/rdbms/admin/utlxplan.sql。--以上是第一次使用时需要进行的必要操作。
4. 用户sqlplus连接数据库,对会话进行如下设置:
Set autotrace -----off/on/trace[only]------explain/statistics,
然后录入sql语句回车即可查看执行计划—推荐;
或者用如下命令行:
Explain plan set statement_id=’myplan1’ for Your sql-statement;
然后查看用户自己的plan_table
--演示Sql-expert的使用,连接到指定数据库,输入sql,显示执行计划或者sql优化结果,图形界面如下:
--ps:但我在使用中发现sql-expert的执行计划有时候显示得并不准确,所以建议以sqlplus中的为准。其sql优化倒很值得参考,有多种结果,用户可以自己测试和选择。
六.SQL优化技巧
在这方面,长期搞数据库应用开发的人应该更有经验,我这里大概总结一下自己遇到过的和搜集到的一些sql优化经验,跟大家共同学习。
SQL语言是一种灵活的语言,相同的功能可以使用不同的语句来实现,但是语句的执行效率可能会很不相同的,生产系统里经常跑的sql语句更要注意执行效率,否则会占用大量系统资源,带慢整个系统。SQL优化的实质就是在结果正确的前提下,用优化器可以识别的语句,充份利用索引,执行过程中访问尽量少的数据块,减少表扫描的I/O次数,尽量避免全表扫描和其他额外开销。
Sql优化:
1、 先介绍一下oracle数据库常用的两种优化器:RBO(rule-based-optimizer)和CBO(cost-based- optimizer)。目前更多地采用CBO(cost-based-optimizer)基于开销的优化器。在CBO方式下,Oracle会根据表及索引的状态信息来选择计划;在RBO方式下,Oracle会根据自己内部设置的一些规则来决定选择计划,例如oracle会根据以下优先级来选择执行计划(越靠前,rank越低,越快):
RANK Access path
1 ROWID等于常量
2 唯一键值或主键的聚簇连接*
3 唯一键值或主键的哈希聚簇连接*
4 整个复合索引等于常量
5 唯一索引列等于常量
6 完全聚簇键等于同一个聚簇上的另一个表对应的聚簇键*
7 哈希聚簇键等于常数*
8 完全聚簇键等于常数*
9 整个非唯一组合索引等于常量
10 非唯一索引连结
11 整个组合索引等于小范围的值
12 组合索引的大部分前面的列等于常量
13 索引列取值存在上限和下限或者索引列LIKE "ABC%"(范围限制)
14 非唯一索引列取值存在上限和下限或者索引列LIKE "ABC%"(范围限制)
15 唯一索引列或是常量(范围无限制)
16 非唯一索引列或是常(范围无限制)
17 非索引列的等值连接(sort/merge join)
18 单一索引列的最大或最小值
19 ORDER BY整个索引
20 全表扫描
2、 创建索引:创建索引一般有以下两个目的:维护被索引列的唯一性和提供快速访问表中数据的策略。
索引创建原则:
--在select操作占大部分的表上创建索引;
--在where子句中出现最频繁的列上创建索引;
--在选择性高的列上创建索引(补充索引选择性,最高是1,eg:primary key)
--复合索引的主列应该是最有选择性的和where限定条件最常用的列,并以此类推第二列……。
--小于5M的表,最好不要使用索引来查询,表越小,越适合用全表扫描。
索引使用原则:
--查询结果是所有数据行的5%以下时,使用index查询效果最好;
--where条件中经常用到表的多列时,使用复合索引效果会好于几个单列索引。因为当sql 语句所查询的列,全部都出现在复合索引中时,此时由于 Oracle 只需要查询索引块即可获得所有数据,当然比使用多个单列索引要快得多;
--索引利于select,但对经常insert,delte尤其update的表,会降低效率。
eg:试比较下面两条SQL语句(emp 表的deptno列上建有ununique index):
语句A:SELECT dname, deptno FROM dept WHERE deptno NOT IN
(SELECT deptno FROM emp);
语句B:SELECT dname, deptno FROM dept WHERE NOT EXISTS
(SELECT deptno FROM emp WHERE dept.deptno = emp.deptno);
这两条查询语句实现的结果是相同的,但是执行语句A的时候,ORACLE会对整个emp表进行扫描,没有使用建立在emp表上的deptno索引,执行语句 B的时候,由于在子查询中使用了联合查询,ORACLE只是对emp表进行的部分数据扫描,并利用了deptno列的索引,所以语句B的效率要比语句A的效率高。我的测试结果:(当emp表有37M时的测试):
SQL> SELECT dname, deptno FROM dept WHERE deptno NOT IN
(SELECT deptno FROM emp);
DNAME DEPTNO
-------------- ----------
OPERATIONS 40
Elapsed: 00:00:01.08
Execution Plan
----------------------------------------------------------
0 SELECT STATEMENT Optimizer=CHOOSE
1 0 FILTER
2 1 TABLE ACCESS (FULL) OF 'DEPT'
3 1 TABLE ACCESS (FULL) OF 'EMP'
Statistics
----------------------------------------------------------
0 recursive calls
31 db block gets
4635 consistent gets
1 physical reads
0 redo size
541 bytes sent via SQL*Net to client
550 bytes received via SQL*Net from client
2 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
1 rows processed
SQL> SELECT dname, deptno FROM dept WHERE NOT EXISTS
(SELECT deptno FROM emp WHERE dept.deptno = emp.deptno);
DNAME DEPTNO
-------------- ----------
OPERATIONS 40
Elapsed: 00:00:00.30
Execution Plan
----------------------------------------------------------
0 SELECT STATEMENT Optimizer=CHOOSE
1 0 FILTER
2 1 TABLE ACCESS (FULL) OF 'DEPT'
3 1 INDEX (RANGE SCAN) OF 'IND_EMP_DEPTNO' (NON-UNIQUE)
Statistics
----------------------------------------------------------
0 recursive calls
12 db block gets
19 consistent gets
0 physical reads
144 redo size
541 bytes sent via SQL*Net to client
550 bytes received via SQL*Net from client
2 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
1 rows processed
3. 索引常用类型,按存储方式分为:B-tree ,bitmap,reverse key index
* B-ree:最常用的一种,又可以分为primary, unique,nonunique,composite,cluster等
* bitmap适用情况:
--该列重复值很高(eg:性别列、分数列ABC级等),最好该列有not null的限制;
--bitmap对大表效果好,且很节省索引空间;
--适合并发度低的表,因为其数据更新时会锁住整个bitmap block;
--使用bitmap索引时,需要加hint强制使用(应该是oracle一个bug)
* Reverse索引:适用于序列生成的数字列,会将index key列值倒序存放,尤其表的更改并发度又比较高时,更适合用reverse索引,这样可以将相似值的行分散到索引的多个叶子节点,降低冲突,提高性能。
根据应用需求在适当列建合适的索引。
4、 Oracle 要使用一个索引,有一些基本要求条件:
----where 子句中的这个字段,必须是复合索引的第一个字段;
eg:一个索引是按 f1, f2, f3的次序建立的,若where 子句是 f2 = : var2, 则因为 f2 不是索引的第1个字段,无法使用该索引。
---- where 子句中的这个字段,不应该参与任何形式的计算:任何对列的操作都将导致表扫描,它包括数据库函数、计算表达式等等,查询时要尽可能将操作移至等号右边。
-- --应尽量熟悉各种操作符对 Oracle 是否使用索引的影响:以下这些操作会显式(explicitly)地阻止 Oracle 使用索引: is null ; is not null ; not in; !=; like ; numeric_col+0;date_col+0; char_col||’ ’; to_char; to_number,to_date 等。
Eg:
Select jobid from mytabs where isReq='0' and to_date (updatedate) >= to_Date ( '2001-7-18', 'YYYY-MM-DD');--updatedate列的索引也不会生效。
5、索引不是越多越好。特别是大量从来或者几乎不用的索引,对系统只有损害。OLTP系统每表超过5个索引即会降低性能, 而且在一个sql 中, Oracle 从不能使用超过 5个索引。
索引对select有正面效果,但对insert,delete尤其是update有负面效果,会影响速度,索引越多,影响越大。所以oracle工具 sqlldr倒入数据时,好的做法是先建好表结构,再倒入数据,最后才建索引,以提高数据倒入的速度,oracle工具import默认就是先倒入数据,然后才建索引。所以建索引时要充分考虑该表的主要应用。
Tips:经常做insert,delete尤其是update的表最好定期 exp/imp表数据,整理数据,降低碎片(缺点:要停应用,以保持数据一致性,不实用);有索引的最好定期rebuild索引(rebuild期间只允许表的select操作,可在数据库较空闲时间提交),以降低索引碎片,提高效率;
6、何时适合使用全表扫描?
--小表,仅有几个data block的表(5M以下);
--对数据行的选择率高于20%时可考虑用全表扫描(如有1000行记录,一次选出200行以上)
7.选择联合查询的联合次序。联合查询分为3种:merge join,nested loop,hash join,这里讲的是nested loop的联合情况(后面实际案例1的优化就属于此类);
考虑下面的例子:
SELECT stuff FROM taba a, tabb b, tabc c
WHERE a.acol between :alow and :ahigh
AND b.bcol between :blow and :bhigh
AND c.ccol between :clow and :chigh
AND a.key1 = b.key1
AMD a.key2 = c.key2;
这个SQL例子中,程序员首先需要选择要查询的主表,因为主表要进行整个表数据的扫描,所以主表应该数据量最小,所以例子中表A的acol列的范围应该比表 B和表C相应列的范围小。内外表的选择可由公式:外层表中的匹配行数*内层表中每一次查找的次数确定,乘积最小为最佳方案。
8、用UNION ALL代替UNION:
UNION是最常用的集操作,使多个记录集联结成为单个集,对返回的数据行有唯一性要求,所以oracle就需要进行SORT UNIQUE操作(与使用distinct时操作类似),如果结果集又比较大,则操作会比较慢;
UNION ALL操作不排除重复记录行,所以会快很多,如果数据本身重复行存在可能性较小时,用union all会比用union效率高很多!
9. 避免在SQL里使用PL/SQL功能调用:
PL/SQL块有利于提高重复使用代码,但是如果混合在SQL语句中,反而会降低效率。Eg:
US$()为一货币转换的PL/SQL
Sql: select name,US$(amount,currency) from salary where US$(amount,currency)>1000;
该sql效率低下,因为混合PL/SQL和sql时,oracle使用的机制不同,执行时,oracle将调用分成两个组件:用带有赋值变量的SQL语句代替功能调用,和对功能调用的PL/SQL块:
即:
select name,:a1 from salary where :a2>1000;
和
begin
:a1:=US$(:amount,:currency);
end;
对salary表里的每一行执行PL/SQL两次,效率大大降低。
10 子查询中慎重使用IN或者NOT IN语句,使用where (NOT) exists的效果要好的多。IN、OR子句常会使索引失效,可以考虑把子句拆开,拆开的子句中尽量包含索引。
11慎重使用视图的联合查询,尤其是比较复杂的视图之间的联合查询。一般对视图的查询最好都分解为对数据表的直接查询效果要好一些。
12 ORACLE提供的DBMS_SHARED_POOL程序可以帮助程序员将某些经常使用的存储过程“钉”在SQL区中而不被换出内存,程序员对于经常使用并且占用内存较多的存储过程“钉”到内存中有利于提高最终用户的响应时间。一定要确认非常有必要时才采用这个方法,否则对系统只有坏的影响,会降低内存利用率。
(execute DBMS_SHARED_POOL.KEEP('APPOWNER.ADD_CLIENT','P');
(P代表PROCEDURES,C代表CURSORS))
13. 从物理存储方面降低竞争,提高索引效率:将索引和数据分开不同的表空间存放,以减少I/O竞争(尽量将索引、数据表空间从物理底蹭分开是数据库建设前期物理设计工作的重要部分)。举例:九七数据库里的TB表(长驻cache;仅几十行数据,并发度高,更新频繁,分多个block存放,降低block I/O竞争)
14.加hint强制使用索引
有时候oracle自动判断的CBO信息不能令人满意时,就需要我们手工加hint来强制sql语句得到我们想要的执行计划。
Hint的基本使用方法:
----紧跟DML(select,insert,delete,update)之后:,;
----sql语句中若使用了别名(aliase),则hint里面也必须使用别名。
--不要对view查询加hint,无效。
Tip:尽量少用hint,因为随着数据变化,可能加hint的执行计划逐渐变的不再是最优;加hint的维护成本较高;
15.使用session/transaction级别的临时表会大大提高中间处理的速度:
---临时表只对本session或者transaction可见,关闭session或者退出transaction时,临时表自动被清理drop;
---其他session/transaction可以建同名的temporary table,用户只对自己的temp table操作;
---临时表使用temp表空间,此类表的DML操作不产生redo log,只产生undo log
---可以在其上建index,index也一样是temporary的,生命阶段同temp table。
create global temporary table tab_name(….);
结语:
Oracle 是否真正使用索引,使用索引是否真正有效,还是必须进行实地的测验。合理的做法是,对所写的复杂的 sql, 在将它写入应用程序之前,先在产品数据库上做一次explain,获得对该 sql 的解析,明确看到 Oracle 是如何执行该sql 的,并进行适当优化调整;
另外,即使是相同的sql语句,也会因为表的大小等原因造成执行计划的不同,所以一定要具体情况具体分析! 如果经常做 explain, 就会发现,喜爱写复杂的 sql 并不是个好习惯,因为过分复杂的sql 其解析计划往往不尽如人意。事实上,将复杂的 sql 拆开,有时候会极大地提高效率,因为能获得很好的优化。
赵春英
2004.5.26 定稿
实际案例:
1、 select 'x' from dh where dhso in (select ogso from og where ogid = 21097023 and ogzt='VALID') and dhcz = 18 and dhzt<>'OVER';
执行情况:no rows selected Elapsed: 00:07:05.98
Execution Plan
----------------------------------------------------------
0 SELECT STATEMENT Optimizer=CHOOSE
1 0 VIEW
2 1 SORT (UNIQUE)
3 2 NESTED LOOPS
4 3 TABLE ACCESS (BY INDEX ROWID) OF 'DH'
5 4 INDEX (RANGE SCAN) OF 'IND_DHCZ_DHZT' (NON-UNIQUE)
6 3 TABLE ACCESS (BY INDEX ROWID) OF 'OG'
7 6 INDEX (UNIQUE SCAN) OF 'PK_OGID_OGSO' (UNIQUE)
Statistics
----------------------------------------------------------
0 recursive calls
0 db block gets
421027 consistent gets
15181 physical reads
1000 redo size
181 bytes sent via SQL*Net to client
278 bytes received via SQL*Net from client
1 SQL*Net roundtrips to/from client
1 sorts (memory)
0 sorts (disk)
0 rows processed
原语句用7分6秒完成,使用sqlexpert优化后选取的一个新语句如下,出结果仅用8秒!
select 'x' from dh
where EXISTS (SELECT 'X' from og WHERE ogid = 21097023 and ogzt = 'VALID' AND ogso = dhso) and dhcz = 18 and dhzt <> 'OVER';
执行情况: no rows selected Elapsed: 00:00:08.23
Execution Plan
----------------------------------------------------------
0 SELECT STATEMENT Optimizer=HINT: ALL_ROWS (Cost=119 Card=55
Bytes=3410)
1 0 TABLE ACCESS (BY INDEX ROWID) OF 'DH' (Cost=2 Card=1 Bytes
=31)
2 1 NESTED LOOPS (Cost=119 Card=55 Bytes=3410)
3 2 SORT (UNIQUE)
4 3 TABLE ACCESS (BY INDEX ROWID) OF 'OG' (Cost=6 Card=5
5 Bytes=1705)
5 4 INDEX (RANGE SCAN) OF 'PK_OGID_OGSO' (UNIQUE) (Cos
t=2 Card=2191)
6 2 INDEX (RANGE SCAN) OF 'IND_DHSO' (NON-UNIQUE) (Cost=1
Card=2018)
Statistics
----------------------------------------------------------
16 recursive calls
0 db block gets
10 consistent gets
1 physical reads
0 redo size
181 bytes sent via SQL*Net to client
278 bytes received via SQL*Net from client
1 SQL*Net roundtrips to/from client
1 sorts (memory)
0 sorts (disk)
0 rows processed
2、select GGZT,GGXX,GGSJ,GGRQ,GGLR,GGGH,GGDH,GGBZ,GGID
from GG where GGRQ>='20040325'
and GGRQ<='20040325' and GGID>8673 and GGZT='VALID' and GGID in
(select GFGG from GF,GB where GFGG=GBGG
and ((GFGW=1 and GFQX>='003' and GBLX='001' and GBDW=104)
or (GFGW=118 and GFQX>='000' and GBLX='002' and GBDW=102)))
order by GGID DESC;
--联合查询三个小表(GG 1M, GB 2M, GF 2M), 用了索引反而慢,又费cpu,优化后改成全表扫描:
执行情况:
no rows selected
Elapsed: 00:00:18.57
Execution Plan
----------------------------------------------------------
0 SELECT STATEMENT Optimizer=CHOOSE
1 0 SORT (ORDER BY)
2 1 VIEW
3 2 SORT (UNIQUE)
4 3 CONCATENATION
5 4 NESTED LOOPS
6 5 NESTED LOOPS
7 6 TABLE ACCESS (BY INDEX ROWID) OF 'GB'
8 7 INDEX (RANGE SCAN) OF 'IND_GBLX_GBDW' (NON-U
NIQUE)
9 6 TABLE ACCESS (BY INDEX ROWID) OF 'GF'
10 9 INDEX (RANGE SCAN) OF 'IND_GFGW' (NON-UNIQUE
)
11 5 TABLE ACCESS (BY INDEX ROWID) OF 'GG'
12 11 INDEX (UNIQUE SCAN) OF 'PK_GGID' (UNIQUE)
13 4 NESTED LOOPS
14 13 NESTED LOOPS
15 14 TABLE ACCESS (BY INDEX ROWID) OF 'GB'
16 15 INDEX (RANGE SCAN) OF 'IND_GBLX_GBDW' (NON-U
NIQUE)
17 14 TABLE ACCESS (BY INDEX ROWID) OF 'GF'
18 17 INDEX (RANGE SCAN) OF 'IND_GFGW' (NON-UNIQUE
)
19 13 TABLE ACCESS (BY INDEX ROWID) OF 'GG'
20 19 INDEX (UNIQUE SCAN) OF 'PK_GGID' (UNIQUE)
Statistics
----------------------------------------------------------
243 recursive calls
0 db block gets
346554 consistent gets
20 physical reads
0 redo size
534 bytes sent via SQL*Net to client
278 bytes received via SQL*Net from client
1 SQL*Net roundtrips to/from client
8 sorts (memory)
0 sorts (disk)
0 rows processed
select GGZT,GGXX,GGSJ,GGRQ,GGLR,GGGH,GGDH,GGBZ,GGID
from GG where GGRQ>='20040325'
and GGRQ<='20040325' and GGID>8673 and GGZT='VALID' and GGID in
(select GFGG from GF,GB where GFGG=GBGG
and ((GFGW=1 and GFQX>='003' and GBLX='001' and GBDW=104)
or (GFGW=118 and GFQX>='000' and GBLX='002' and GBDW=102)))
order by GGID DESC;
执行情况:
no rows selected
Elapsed: 00:00:07.96
Execution Plan
----------------------------------------------------------
0 SELECT STATEMENT Optimizer=CHOOSE (Cost=25 Card=1 Bytes=715)
1 0 SORT (ORDER BY) (Cost=25 Card=1 Bytes=715)
2 1 HASH JOIN (SEMI) (Cost=22 Card=1 Bytes=715)
3 2 TABLE ACCESS (FULL) OF 'GG' (Cost=3 Card=1 Bytes=702)
4 2 VIEW OF 'VW_NSO_1' (Cost=18 Card=1 Bytes=13)
5 4 HASH JOIN (Cost=18 Card=1 Bytes=62)
6 5 TABLE ACCESS (BY INDEX ROWID) OF 'GB' (Cost=4 Card
=1041 Bytes=32271)
7 6 BITMAP CONVERSION (TO ROWIDS)
8 7 BITMAP OR
9 8 BITMAP CONVERSION (FROM ROWIDS)
10 9 INDEX (RANGE SCAN) OF 'IND_GBLX_GBDW' (NON
-UNIQUE) (Cost=1)
11 8 BITMAP CONVERSION (FROM ROWIDS)
12 11 INDEX (RANGE SCAN) OF 'IND_GBLX_GBDW' (NON
-UNIQUE) (Cost=1)
13 5 TABLE ACCESS (FULL) OF 'GF' (Cost=13 Card=1213 Byt
es=37603)
Statistics
----------------------------------------------------------
390 recursive calls
0 db block gets
82 consistent gets
4 physical reads
0 redo size
534 bytes sent via SQL*Net to client
278 bytes received via SQL*Net from client
1 SQL*Net roundtrips to/from client
1 sorts (memory)
0 sorts (disk)
0 rows processed