索引使用的注意點(diǎn)

          1)????? 合理使用索引

          索引是數(shù)據(jù)庫(kù)中重要的數(shù)據(jù)結(jié)構(gòu),它的根本目的就是為了提高查詢效率。現(xiàn)在大多數(shù)的數(shù)據(jù)庫(kù)產(chǎn)品都采用 IBM 最先提出的 ISAM 索引結(jié)構(gòu)。索引的使用要恰到好處,其使用原則如下:

          ●在經(jīng)常進(jìn)行連接,但是沒(méi)有指定為外鍵的列上建立索引,而不經(jīng)常連接的字段則由優(yōu)化器自動(dòng)生成索引。

          ●在頻繁進(jìn)行排序或分組(即進(jìn)行 group by order by 操作)的列上建立索引。

          ●在條件表達(dá)式中經(jīng)常用到的不同值較多的列上建立檢索,在不同值少的列上不要建立索引。比如在雇員表的“性別”列上只有“男”與“女”兩個(gè)不同值,因此就無(wú)必要建立索引。如果建立索引不但不會(huì)提高查詢效率,反而會(huì)嚴(yán)重降低更新速度。

          ●如果待排序的列有多個(gè),可以在這些列上建立復(fù)合索引( compound index )。

          ●使用系統(tǒng)工具。如 Informix 數(shù)據(jù)庫(kù)有一個(gè) tbcheck 工具,可以在可疑的索引上進(jìn)行檢查。在一些數(shù)據(jù)庫(kù)服務(wù)器上,索引可能失效或者因?yàn)轭l繁操作而使得讀取效率降低,如果一個(gè)使用索引的查詢不明不白地慢下來(lái),可以試著用 tbcheck 工具檢查索引的完整性,必要時(shí)進(jìn)行修復(fù)。另外,當(dāng)數(shù)據(jù)庫(kù)表更新大量數(shù)據(jù)后,刪除并重建索引可以提高查詢速度。

          2)????? 避免或簡(jiǎn)化排序

          應(yīng)當(dāng)簡(jiǎn)化或避免對(duì)大型表進(jìn)行重復(fù)的排序。當(dāng)能夠利用索引自動(dòng)以適當(dāng)?shù)拇涡虍a(chǎn)生輸出時(shí),優(yōu)化器就避免了排序的步驟。以下是一些影響因素:

          ●索引中不包括一個(gè)或幾個(gè)待排序的列;

          group by order by 子句中列的次序與索引的次序不一樣;

          ●排序的列來(lái)自不同的表。

          為了避免不必要的排序,就要正確地增建索引,合理地合并數(shù)據(jù)庫(kù)表(盡管有時(shí)可能影響表的規(guī)范化,但相對(duì)于效率的提高是值得的)。如果排序不可避免,那么應(yīng)當(dāng)試圖簡(jiǎn)化它,如縮小排序的列的范圍等。

          3)????? 消除對(duì)大型表行數(shù)據(jù)的順序存取

          在嵌套查詢中,對(duì)表的順序存取對(duì)查詢效率可能產(chǎn)生致命的影響。比如采用順序存取策略,一個(gè)嵌套 3 層的查詢,如果每層都查詢 1000 行,那么這個(gè)查詢就要查詢 10 億行數(shù)據(jù)。避免這種情況的主要方法就是對(duì)連接的列進(jìn)行索引。例如,兩個(gè)表:學(xué)生表(學(xué)號(hào)、姓名、年齡……)和選課表(學(xué)號(hào)、課程號(hào)、成績(jī))。如果兩個(gè)表要做連接,就要在“學(xué)號(hào)”這個(gè)連接字段上建立索引。

          還可以使用并集來(lái)避免順序存取。盡管在所有的檢查列上都有索引,但某些形式的 where 子句強(qiáng)迫優(yōu)化器使用順序存取。下面的查詢將強(qiáng)迫對(duì) orders 表執(zhí)行順序操作:

          SELECT FROM orders WHERE (customer_num=104 AND order_num>1001) OR order_num=1008

          雖然在 customer_num order_num 上建有索引,但是在上面的語(yǔ)句中優(yōu)化器還是使用順序存取路徑掃描整個(gè)表。因?yàn)檫@個(gè)語(yǔ)句要檢索的是分離的行的集合,所以應(yīng)該改為如下語(yǔ)句:

          SELECT FROM orders WHERE customer_num=104 AND order_num>1001

          UNION

          SELECT FROM orders WHERE order_num=1008

          這樣就能利用索引路徑處理查詢。

          4)????? 避免相關(guān)子查詢

          一個(gè)列的標(biāo)簽同時(shí)在主查詢和 where 子句中的查詢中出現(xiàn),那么很可能當(dāng)主查詢中的列值改變之后,子查詢必須重新查詢一次。查詢嵌套層次越多,效率越低,因此應(yīng)當(dāng)盡量避免子查詢。如果子查詢不可避免,那么要在子查詢中過(guò)濾掉盡可能多的行。

          5)????? 避免困難的正規(guī)表達(dá)式

          MATCHES LIKE 關(guān)鍵字支持通配符匹配,技術(shù)上叫正規(guī)表達(dá)式。但這種匹配特別耗費(fèi)時(shí)間。例如: SELECT FROM customer WHERE zipcode LIKE 98_ _ _

          即使在 zipcode 字段上建立了索引,在這種情況下也還是采用順序掃描的方式。如果把語(yǔ)句改為 SELECT FROM customer WHERE zipcode > 98000 ”,在執(zhí)行查詢時(shí)就會(huì)利用索引來(lái)查詢,顯然會(huì)大大提高速度。

          另外,還要避免非開始的子串。例如語(yǔ)句: SELECT FROM customer WHERE zipcode[2 3] > 80 ”,在 where 子句中采用了非開始子串,因而這個(gè)語(yǔ)句也不會(huì)使用索引。

          6)????? 使用臨時(shí)表加速查詢

          把表的一個(gè)子集進(jìn)行排序并創(chuàng)建臨時(shí)表,有時(shí)能加速查詢。它有助于避免多重排序操作,而且在其他方面還能簡(jiǎn)化優(yōu)化器的工作。例如:

          SELECT cust.name rcvbles.balance ,…… other columns

          FROM cust rcvbles

          WHERE cust.customer_id = rcvlbes.customer_id

          AND rcvblls.balance>0

          AND cust.postcode>“98000”

          ORDER BY cust.name

          如果這個(gè)查詢要被執(zhí)行多次而不止一次,可以把所有未付款的客戶找出來(lái)放在一個(gè)臨時(shí)文件中,并按客戶的名字進(jìn)行排序:

          SELECT cust.name rcvbles.balance ,…… other columns

          FROM cust rcvbles

          WHERE cust.customer_id = rcvlbes.customer_id

          AND rcvblls.balance>0

          ORDER BY cust.name

          INTO TEMP cust_with_balance

          然后以下面的方式在臨時(shí)表中查詢:

          SELECT FROM cust_with_balance

          WHERE postcode>“98000”

          臨時(shí)表中的行要比主表中的行少,而且物理順序就是所要求的順序,減少了磁盤 I/O ,所以查詢工作量可以得到大幅減少。

          注意:臨時(shí)表創(chuàng)建后不會(huì)反映主表的修改。在主表中數(shù)據(jù)頻繁修改的情況下,注意不要丟失數(shù)據(jù)。

          7)????? 用排序來(lái)取代非順序存取

          非順序磁盤存取是最慢的操作,表現(xiàn)在磁盤存取臂的來(lái)回移動(dòng)。 SQL 語(yǔ)句隱藏了這一情況,使得我們?cè)趯憫?yīng)用程序時(shí)很容易寫出要求存取大量非順序頁(yè)的查詢。

          有些時(shí)候,用數(shù)據(jù)庫(kù)的排序能力來(lái)替代非順序的存取能改進(jìn)查詢。

          ?

          優(yōu)化SQL語(yǔ)句

          ?

          優(yōu)化就是選擇最有效的方法來(lái)執(zhí)行 SQL 語(yǔ)句。 Oracle 優(yōu)化器選擇它認(rèn)為最有效的方法來(lái)執(zhí)行 SQL 語(yǔ)句。  

          1)????? IS NULL IS NOT NULL

          如果某列存在 NULL 值,即使對(duì)該列建立索引也不會(huì)提高性能。

          2)????? 為不同的工作編寫不同的SQL語(yǔ)句塊。

          為完成不同的工作編寫一大塊 SQL 程序不是好方法。它往往導(dǎo)致每個(gè)任務(wù)的結(jié)果不優(yōu)

          化。若要 SQL 完成不同的工作,一般應(yīng)編寫不同的語(yǔ)句塊比編寫一個(gè)要好。

          3)????? IN 和EXISTS

          Select name from employee where name not in (select name from student);

          Select name from employee where not exists (select name from student);

          第一句 SQL 語(yǔ)句的執(zhí)行效率不如第二句。

          通過(guò)使用 EXISTS Oracle 會(huì)首先檢查主查詢,然后運(yùn)行子查詢直到它找到第一個(gè)匹配

          項(xiàng),這就節(jié)省了時(shí)間。 Oracle 在執(zhí)行 IN 子查詢時(shí),首先執(zhí)行子查詢,并將獲得的結(jié)果

          列表存放在一個(gè)加了索引的臨時(shí)表中。在執(zhí)行子查詢之前,系統(tǒng)先將主查詢掛起,待

          子查詢執(zhí)行完畢,存放在臨時(shí)表中以后再執(zhí)行主查詢。這也就是使用 EXISTS 比使用 IN

          通常查詢速度快的原因。

          4)????? NOT 運(yùn)算符

          Select * from employee where salary<>1000;

          Select * from employee where salary<1000 or salary>1000;

          第一句 SQL 語(yǔ)句的執(zhí)行效率不如第二句,因?yàn)榈诙?/span> SQL 語(yǔ)句可以使用索引。

          5)????? Order By 語(yǔ)句

          Order By 語(yǔ)句的執(zhí)行效率很低,因?yàn)樗判颉?yīng)避免在 Order By 字句中使用表達(dá)式。

          6)????? 列的連接

          select * from employee where name||department=’ZYZBIOINFO’;

          select * from employee where name=’ZYZ’ and department=’BIOINFO’;

          這兩個(gè)查詢,第二句比第一句會(huì)快,因?yàn)閷?duì)于有連接運(yùn)算符’ || ’的查詢 ,Oracle 優(yōu)化器是不

          會(huì)使用索引的。

          7)????? 通配符‘%’當(dāng)通配符出現(xiàn)在搜索詞首時(shí),Oracle優(yōu)化器不使用索引。

          Select * from employee where name like ‘%Z%’;

          Select * from employee where name like ‘Z%’;

          第二句的執(zhí)行效率會(huì)比第一句快,但查詢結(jié)果集可能會(huì)不同。

          8)????? 應(yīng)盡量避免混合類型的表達(dá)式。

          假設(shè)字段 studentno VARCHAR2 類型

          有語(yǔ)句 select * from student where studentno>123;

          Oracle 會(huì)有一個(gè)隱含的類型轉(zhuǎn)換。隱含的類型轉(zhuǎn)換可能會(huì)使 Oracle 優(yōu)化器忽略索引。

          這時(shí)應(yīng)使用顯式的類型轉(zhuǎn)換 select * from student where studentno=to_char(123)

          9)????? DISTINCT

             DISTINCT 總是建立一個(gè)排序,所以查詢速度也慢。

          posted on 2006-05-09 17:38 野草 閱讀(640) 評(píng)論(0)  編輯  收藏 所屬分類: oracle
          主站蜘蛛池模板: 惠水县| 航空| 轮台县| 乌兰察布市| 灌阳县| 肃北| 远安县| 永清县| 清新县| 英山县| 镇平县| 罗田县| 岱山县| 鲜城| 县级市| 南部县| 卢湾区| 景泰县| 滕州市| 于田县| 廉江市| 大化| 柞水县| 宁城县| 通山县| 定边县| 临清市| 南川市| 镇赉县| 宁陵县| 大足县| 扶绥县| 宕昌县| 德钦县| 韩城市| 耒阳市| 开封市| 固阳县| 汽车| 荔浦县| 枞阳县|