(作者:福州電信局計(jì)算機(jī)中心 李炯 2000年05月15日 18:17)
當(dāng)你運(yùn)用SQL語言,向數(shù)據(jù)庫發(fā)布一條查詢語句時(shí),ORACLE將伴隨產(chǎn)生一個(gè)“執(zhí)行計(jì)劃”,也就是該語句將通過何種數(shù)據(jù)搜索方案執(zhí)行,是通過全表掃描、還是通過索引搜尋等其它方式。搜索方案的選用與ORACLE的優(yōu)化器息息相關(guān)。
SQL語句的執(zhí)行步驟
一條SQL語句的處理過程要經(jīng)過以下幾個(gè)步驟。
1 語法分析 分析語句的語法是否符合規(guī)范,衡量語句中各表達(dá)式的意義。
2 語義分析 檢查語句中涉及的所有數(shù)據(jù)庫對(duì)象是否存在,且用戶有相應(yīng)的權(quán)限。
3 視圖轉(zhuǎn)換 將涉及視圖的查詢語句轉(zhuǎn)換為相應(yīng)的對(duì)基表查詢語句。
4 表達(dá)式轉(zhuǎn)換 將復(fù)雜的SQL表達(dá)式轉(zhuǎn)換為較簡(jiǎn)單的等效連接表達(dá)式。
5 選擇優(yōu)化器 不同的優(yōu)化器一般產(chǎn)生不同的“執(zhí)行計(jì)劃”
6 選擇連接方式 ORACLE有三種連接方式,對(duì)多表連接ORACLE可選擇適當(dāng)?shù)倪B接方式。
7 選擇連接順序 對(duì)多表連接ORACLE選擇哪一對(duì)表先連接,選擇這兩表中哪個(gè)表做為源數(shù)據(jù)表。
8 選擇數(shù)據(jù)的搜索路徑 根據(jù)以上條件選擇合適的數(shù)據(jù)搜索路徑,如是選用全表搜索還是利用索引或是其他的方式。
9 運(yùn)行“執(zhí)行計(jì)劃”
ORACLE的優(yōu)化器
ORACLE有兩種優(yōu)化器:基于規(guī)則的優(yōu)化器(RBO, Rule Based Optimizer),和基于代價(jià)的優(yōu)化器(CBO, Cost Based Optimizer)。
RBO自O(shè)RACLE 6版以來被采用,有著一套嚴(yán)格的使用規(guī)則,只要你按照它去寫SQL語句,無論數(shù)據(jù)表中的內(nèi)容怎樣,也不會(huì)影響到你的“執(zhí)行計(jì)劃”,也就是說對(duì)數(shù)據(jù)不“敏感”,ORACLE公司已經(jīng)不再發(fā)展這種技術(shù)了。
CBO自O(shè)RACLE 7版被引入,ORACLE自7版以來采用的許多新技術(shù)都是基于CBO的,如星型連接排列查詢,哈希連接查詢,和并行查詢等。CBO計(jì)算各種可能“執(zhí)行計(jì)劃”的“代價(jià)”,即cost,從中選用cost最低的方案,作為實(shí)際運(yùn)行方案。各“執(zhí)行計(jì)劃”的cost的計(jì)算根據(jù),依賴于數(shù)據(jù)表中數(shù)據(jù)的統(tǒng)計(jì)分布,ORACLE數(shù)據(jù)庫本身對(duì)該統(tǒng)計(jì)分布并不清楚,須要分析表和相關(guān)的索引,才能搜集到CBO所需的數(shù)據(jù)。
一般而言,CBO所選擇的“執(zhí)行計(jì)劃”都不會(huì)比RBO的“執(zhí)行計(jì)劃”差,而且相對(duì)而言,CBO對(duì)程序員的要求沒有RBO那么苛刻,節(jié)省了程序員為了從多個(gè)可能的“執(zhí)行計(jì)劃”中選擇一個(gè)最優(yōu)的方案而花費(fèi)的調(diào)試時(shí)間,但在某些場(chǎng)合下也會(huì)存在問題。
較典型的問題有:有時(shí),表明明建有索引,但查詢過程顯然沒有用到相關(guān)的索引,導(dǎo)致查詢過程耗時(shí)漫長,占用資源巨大,問題到底出在哪兒呢?按照以下順序查找,基本上能發(fā)現(xiàn)原因所在。
查找原因的步驟
首先,我們要確定數(shù)據(jù)庫運(yùn)行在何種優(yōu)化模式下,相應(yīng)的參數(shù)是:optimizer_mode。可在svrmgrl中運(yùn)行“show parameter optimizer_mode"來查看。ORACLE V7以來缺省的設(shè)置應(yīng)是"choose",即如果對(duì)已分析的表查詢的話選擇CBO,否則選擇RBO。如果該參數(shù)設(shè)為“rule”,則不論表是否分析過,一概選用RBO,除非在語句中用hint強(qiáng)制。
其次,檢查被索引的列或組合索引的首列是否出現(xiàn)在PL/SQL語句的WHERE子句中,這是“執(zhí)行計(jì)劃”能用到相關(guān)索引的必要條件。
第三,看采用了哪種類型的連接方式。ORACLE的共有Sort Merge Join(SMJ)、Hash Join(HJ)和Nested Loop Join(NL)。在兩張表連接,且內(nèi)表的目標(biāo)列上建有索引時(shí),只有Nested Loop才能有效地利用到該索引。SMJ即使相關(guān)列上建有索引,最多只能因索引的存在,避免數(shù)據(jù)排序過程。HJ由于須做HASH運(yùn)算,索引的存在對(duì)數(shù)據(jù)查詢速度幾乎沒有影響。
第四,看連接順序是否允許使用相關(guān)索引。假設(shè)表emp的deptno列上有索引,表dept的列deptno上無索引,WHERE語句有emp.deptno=dept.deptno條件。在做NL連接時(shí),emp做為外表,先被訪問,由于連接機(jī)制原因,外表的數(shù)據(jù)訪問方式是全表掃描,emp.deptno上的索引顯然是用不上,最多在其上做索引全掃描或索引快速全掃描。
第五,是否用到系統(tǒng)數(shù)據(jù)字典表或視圖。由于系統(tǒng)數(shù)據(jù)字典表都未被分析過,可能導(dǎo)致極差的“執(zhí)行計(jì)劃”。但是不要擅自對(duì)數(shù)據(jù)字典表做分析,否則可能導(dǎo)致死鎖,或系統(tǒng)性能下降。
第六,索引列是否函數(shù)的參數(shù)。如是,索引在查詢時(shí)用不上。
第七,是否存在潛在的數(shù)據(jù)類型轉(zhuǎn)換。如將字符型數(shù)據(jù)與數(shù)值型數(shù)據(jù)比較,ORACLE會(huì)自動(dòng)將字符型用to_number()函數(shù)進(jìn)行轉(zhuǎn)換,從而導(dǎo)致第六種現(xiàn)象的發(fā)生。
第八,是否為表和相關(guān)的索引搜集足夠的統(tǒng)計(jì)數(shù)據(jù)。對(duì)數(shù)據(jù)經(jīng)常有增、刪、改的表最好定期對(duì)表和索引進(jìn)行分析,可用SQL語句“analyze table xxxx compute statistics for all indexes;"。ORACLE掌握了充分反映實(shí)際的統(tǒng)計(jì)數(shù)據(jù),才有可能做出正確的選擇。
第九,索引列的選擇性不高。
我們假設(shè)典型情況,有表emp,共有一百萬行數(shù)據(jù),但其中的emp.deptno列,數(shù)據(jù)只有4種不同的值,如10、20、30、40。雖然emp數(shù)據(jù)行有很多,ORACLE缺省認(rèn)定表中列的值是在所有數(shù)據(jù)行均勻分布的,也就是說每種deptno值各有25萬數(shù)據(jù)行與之對(duì)應(yīng)。假設(shè)SQL搜索條件DEPTNO=10,利用deptno列上的索引進(jìn)行數(shù)據(jù)搜索效率,往往不比全表掃描的高,ORACLE理所當(dāng)然對(duì)索引“視而不見”,認(rèn)為該索引的選擇性不高。
但我們考慮另一種情況,如果一百萬數(shù)據(jù)行實(shí)際不是在4種deptno值間平均分配,其中有99萬行對(duì)應(yīng)著值10,5000行對(duì)應(yīng)值20,3000行對(duì)應(yīng)值30,2000行對(duì)應(yīng)值40。在這種數(shù)據(jù)分布圖案中對(duì)除值為10外的其它deptno值搜索時(shí),毫無疑問,如果索引能被應(yīng)用,那么效率會(huì)高出很多。我們可以采用對(duì)該索引列進(jìn)行單獨(dú)分析,或用analyze語句對(duì)該列建立直方圖,對(duì)該列搜集足夠的統(tǒng)計(jì)數(shù)據(jù),使ORACLE在搜索選擇性較高的值能用上索引。
第十,索引列值是否可為空(NULL)。如果索引列值可以是空值,在SQL語句中那些需要返回NULL值的操作,將不會(huì)用到索引,如COUNT(*),而是用全表掃描。這是因?yàn)樗饕写鎯?chǔ)值不能為全空。
第十一,看是否有用到并行查詢(PQO)。并行查詢將不會(huì)用到索引。
第十二,看PL/SQL語句中是否有用到bind變量。由于數(shù)據(jù)庫不知道bind變量具體是什么值,在做非相等連接時(shí),如“<”,“>”,“l(fā)ike”等。ORACLE將引用缺省值,在某些情況下會(huì)對(duì)執(zhí)行計(jì)劃造成影響。
如果從以上幾個(gè)方面都查不出原因的話,我們只好用采用在語句中加hint的方式強(qiáng)制ORACLE使用最優(yōu)的“執(zhí)行計(jì)劃”。
hint采用注釋的方式,有行注釋和段注釋兩種方式。
如我們想要用到A表的IND_COL1索引的話,可采用以下方式:
“SELECT * FROM A WHERE COL1 = XXX;"
注意,注釋符必須跟在SELECT之后,且注釋中的“+”要緊跟著注釋起始符“ |
# --
|
當(dāng)作計(jì)算器 |
SQL> select 1+1 from dual; |
mysql> select 1+1; |
限制返回記錄條數(shù) |
SQL> select * from 表名 where rownum
|
mysql> select * from 表名 limit 5; |
新建用戶(庫) |
SQL> create user 用戶名 identified by 密碼; |
mysql> create database 庫名; |
刪用戶(庫) |
SQL> drop user 用戶名; |
mysql> drop database 庫名; |
外連接 |
使用(+) |
使用left join |
查詢索引 |
SQL> select index_name,table_name from user_indexes; |
mysql> show index from 表名 [FROM 庫名]; |
通配符 |
“%” |
“%”和“_” |
SQL語法 |
SELECT selection_list 選擇哪些列
FROM table_list 從何處選擇行
WHERE primary_constraint 行必須滿足什么條件
GROUP BY grouping_columns 怎樣對(duì)結(jié)果分組
HAVING secondary_constraint 行必須滿足的第二條件
ORDER BY sorting_columns 怎樣對(duì)結(jié)果排序
|
SELECT selection_list 選擇哪些列
FROM table_list 從何處選擇行
WHERE primary_constraint 行必須滿足什么條件
GROUP BY grouping_columns 怎樣對(duì)結(jié)果分組
HAVING secondary_constraint 行必須滿足的第二條件
ORDER BY sorting_columns 怎樣對(duì)結(jié)果排序
LIMIT count 結(jié)果限定
|