一、 先介紹一下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)之后:/*+hint_content*/,/*和+之間不能有空格;或者用--+,此行后面均為hint內容;
----一句sql只能有一個hint,但里面可以有多層,eg:/*+hint1,hint2…*/;
----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 /*+ ALL_ROWS */ '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 /*+ full(gg) */ 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 /*+ full(gf) */ 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