索引:
最常用的索引包括:B*樹索引、位圖索引、位圖聯(lián)合索引、基于函數(shù)索引、應(yīng)用域索引
1 B*書索引:實(shí)現(xiàn)快速定位,數(shù)據(jù)庫(kù)會(huì)根據(jù)所索引的列來(lái)建立索引,如果該列是唯一的就將該列進(jìn)行排序,然后建立索引,如果該列不唯一則加入rowid列,使其達(dá)到唯一,然后進(jìn)行排序,借用oracle編程藝術(shù)中的圖:

B*樹索引包括如下幾種:
普通索引
反向鍵索引:將索引列用reverse函數(shù)反序后建立索引,這是為了避免當(dāng)同時(shí)插入數(shù)據(jù)太多,導(dǎo)致同一個(gè)索引塊忙碌的情況,比如同時(shí)插入1w個(gè)記錄,這1w個(gè)記錄就會(huì)同時(shí)在一個(gè)索引塊里創(chuàng)建索引,導(dǎo)致該塊忙碌,影響性能
降序索引:索引默認(rèn)是按照索引列遞增的順序進(jìn)行排序的,如果索引列是遞減的也可以用默認(rèn)的索引,畢竟倒過(guò)來(lái)就是遞減的;但是如果索引列有2個(gè)字段,而當(dāng)我查詢的時(shí)候一個(gè)是asc,一個(gè)是desc,這時(shí)候默認(rèn)索引到不到預(yù)期的效果;但是如果給遞減列用上降序索引,的增列用上默認(rèn)索引的話,那么性能會(huì)大幅提高;
關(guān)于聚簇因子:oracle有一個(gè)表叫user_indexes,在這里可以查詢所有的索引,比如執(zhí)行查詢
如果clustering_factor非常接近blocks,說(shuō)明數(shù)據(jù)非常有序,連續(xù)的數(shù)據(jù)可能在一個(gè)塊中,這樣進(jìn)行區(qū)間段等大數(shù)據(jù)查詢的時(shí)候,性能越高
如果clustering_factor非常接近num_rows,說(shuō)明數(shù)據(jù)非常隨即。索引條目指向的數(shù)據(jù)不一定在一個(gè)快中,進(jìn)行區(qū)間等查詢的時(shí)候,性能很差
B*樹索引應(yīng)用場(chǎng)合:1 僅僅返回少數(shù)數(shù)據(jù),數(shù)據(jù)重復(fù)度低;2 直接用索引能完成,沒(méi)有涉及到表(比如select count(x) where x='xx',這種語(yǔ)句直接檢索索引,根本接觸不到表本身,速度顯然很快)
2 位圖索引:對(duì)于頻繁更新的表,不適合建立位圖索引;位圖索引會(huì)記錄該列的數(shù)據(jù)1存放在1,3,4,7...行,數(shù)據(jù)2存放在2,5,6...行,數(shù)據(jù)null存放在8,9...行等等,會(huì)把所有數(shù)據(jù)及其位置都記錄下來(lái);
所以,數(shù)據(jù)的重復(fù)度越高,越適合位圖索引;如何衡量呢,就是不同相數(shù)據(jù)的個(gè)數(shù)除以總行數(shù)越接近零越好;偽代碼:count(distinct(col))/count(*)越接近零,越適合做位圖索引;
以上數(shù)據(jù)不應(yīng)該建立B*樹索引,因?yàn)锽*樹是樹形結(jié)構(gòu),而重復(fù)度高的數(shù)據(jù),會(huì)根據(jù)一個(gè)值檢索到大量的數(shù)據(jù)。這違背了b*樹索引的原則。
如果進(jìn)行查詢select count(*) from Table1 where col1='x' or col1='y',這個(gè)就會(huì)用到位圖索引,只是將2個(gè)合并,都不會(huì)去查詢表,在索引中直接返回正確結(jié)果
如果進(jìn)行查詢select * from table1 wwhere col1='x' or col1='y',這個(gè)會(huì)用到位圖索引,oracle會(huì)到位圖索引去找到所有x和y的索引,然后找到相應(yīng)的rowid,然后根據(jù)rowid快速返回結(jié)果集
對(duì)于頻繁更新的表,為什么不適合用位圖索引:一個(gè)位圖索引中維護(hù)了一個(gè)數(shù)據(jù)和多個(gè)行的位置,如果一個(gè)會(huì)話修改了該列某一行的指定數(shù)據(jù),比如xx1,那么該位圖索引所維護(hù)的xx1數(shù)據(jù)的所有行都會(huì)被鎖定;oracle是無(wú)法鎖定一個(gè)位圖索引中的某一個(gè)行的。這樣就會(huì)出現(xiàn)如下問(wèn)題:
如果該數(shù)據(jù)有100行,那么更新一行的時(shí)候,100行數(shù)據(jù)均被鎖定,導(dǎo)致其他會(huì)話只能等待期釋放之后才能操作;如果頻繁出現(xiàn)這種情況的話,性能會(huì)嚴(yán)重下降。
3 位圖聯(lián)結(jié)索引:這是oracle9i所引入的一個(gè)索引;對(duì)于關(guān)聯(lián)表建立位圖索引,比如有一個(gè)部門表和員工表,員工表中存放了部門表的主鍵,此時(shí)想根據(jù)部門的name來(lái)查詢所有的員工,這是如果建立和位圖聯(lián)結(jié)索引,聚會(huì)很快得到結(jié)果集;
4 基于函數(shù)的索引(待續(xù))
關(guān)于索引常見的問(wèn)題:
1 視圖能建立索引嗎:視圖引用的是基本表,只需要對(duì)基本表建立索引,就相當(dāng)于在視圖中建立索引;
2 Null和索引的協(xié)作:
-- B*樹索引不能建立在都可以為null的列上,因?yàn)锽*書索引會(huì)過(guò)濾掉null,也就是說(shuō),當(dāng)進(jìn)行查詢的時(shí)候:
比如在col1和col2上建立了索引,col1和col2都可以為空,查詢select * from table1 where col1 is null 這個(gè)語(yǔ)句不會(huì)使用索引,因?yàn)槿绻褂盟饕脑挘赡軙?huì)丟失數(shù)據(jù)(那些null的數(shù)據(jù)會(huì)丟失);因?yàn)樗饕裏o(wú)法建立在都可以為null的列上,oracle優(yōu)化器會(huì)選擇不使用索引,而是全表掃描;
3 外鍵是否可以建立索引:在以下情況中,最好在外鍵上建索引
a 如果經(jīng)常進(jìn)行聯(lián)機(jī)刪除或者修改父表主鍵的情況,建議在子表外鍵上建立索引。如果不建立索引的話,有上述操作時(shí),oracle會(huì)把整個(gè)子表全部鎖死,這也是oracle出現(xiàn)死鎖的情況,嚴(yán)重影響系統(tǒng)性能;
b 從父表查詢子表信息的時(shí)候,比如根據(jù)deptName查詢?cè)摬块T下所有員工信息的時(shí)候,建議在子表外鍵上建立索引,或者建立位圖聯(lián)結(jié)索引,否則如果頻繁進(jìn)行上述查詢的話,速度會(huì)很慢,因?yàn)槊看味紝?duì)員工表進(jìn)行了全表掃描。
4 索引為何失效
a 關(guān)于B*樹索引,如果是a、b兩列建立索引,如果a、b兩列都允許為空的話,由于在全是null的數(shù)據(jù)上不會(huì)建立索引,所以為了避免查詢數(shù)據(jù)不準(zhǔn)確,優(yōu)化器會(huì)放棄使用索引,而是使用全表掃描;
b 關(guān)于B*樹索引,如果是a、b兩列建立索引,如果這樣select * from table1 where b =5;此時(shí)如果a列的數(shù)據(jù)重復(fù)率不高的話,如果用索引的話,會(huì)去檢索每條索引的數(shù)據(jù),這樣優(yōu)化器更傾向于用全表掃描;如果a數(shù)據(jù)重復(fù)度很高,優(yōu)化器會(huì)用一種跳躍式掃描方式,此時(shí)會(huì)用上索引;
c 如果用到了函數(shù),比如select * from table1 where f(a) = xx;此時(shí)不會(huì)用到索引,因?yàn)樗饕墙⒃赼上的,而不是建立在f(a)上的;
d 如果a列是字符類型,但是我們執(zhí)行了select * from table1 where a = 5;此時(shí)其實(shí)是隱式的應(yīng)用了to_number(a)=5;索引是建立在a上,而不是建立在函數(shù)上的;
e 有些時(shí)候oracle的優(yōu)化器會(huì)智能的判斷使用索引后是否會(huì)提高效率,如果不會(huì)提高效率那么優(yōu)化器會(huì)自動(dòng)放棄索引,而執(zhí)行full table;此時(shí)請(qǐng)檢查索引的合理性;
oracle編程藝術(shù)上說(shuō):歸根結(jié)底,原因通常就是
“不能使用索引,使用索引會(huì)返回不正確的結(jié)果”
“不應(yīng)該使用索引,使用了,性能會(huì)變得很糟糕”
另外:如果是兩個(gè)列建立索引,那么哪個(gè)放前面,哪個(gè)放后面呢:
這個(gè)要視情況而定,如果只有如下查詢select * from table1 where a= :x and b= :y,那么哪個(gè)在前面都無(wú)所謂;
如果還有這種方式:select * from table1 where b = :y ,那么需要b列在前面;
oracle編程藝術(shù)中還就索引壓縮做出對(duì)比,這里不記錄了。以上都是個(gè)人理解記錄,都是為了方便自己。
最常用的索引包括:B*樹索引、位圖索引、位圖聯(lián)合索引、基于函數(shù)索引、應(yīng)用域索引
1 B*書索引:實(shí)現(xiàn)快速定位,數(shù)據(jù)庫(kù)會(huì)根據(jù)所索引的列來(lái)建立索引,如果該列是唯一的就將該列進(jìn)行排序,然后建立索引,如果該列不唯一則加入rowid列,使其達(dá)到唯一,然后進(jìn)行排序,借用oracle編程藝術(shù)中的圖:
B*樹索引包括如下幾種:
普通索引
反向鍵索引:將索引列用reverse函數(shù)反序后建立索引,這是為了避免當(dāng)同時(shí)插入數(shù)據(jù)太多,導(dǎo)致同一個(gè)索引塊忙碌的情況,比如同時(shí)插入1w個(gè)記錄,這1w個(gè)記錄就會(huì)同時(shí)在一個(gè)索引塊里創(chuàng)建索引,導(dǎo)致該塊忙碌,影響性能
降序索引:索引默認(rèn)是按照索引列遞增的順序進(jìn)行排序的,如果索引列是遞減的也可以用默認(rèn)的索引,畢竟倒過(guò)來(lái)就是遞減的;但是如果索引列有2個(gè)字段,而當(dāng)我查詢的時(shí)候一個(gè)是asc,一個(gè)是desc,這時(shí)候默認(rèn)索引到不到預(yù)期的效果;但是如果給遞減列用上降序索引,的增列用上默認(rèn)索引的話,那么性能會(huì)大幅提高;
關(guān)于聚簇因子:oracle有一個(gè)表叫user_indexes,在這里可以查詢所有的索引,比如執(zhí)行查詢
select a.index_name,b.num_rows,b.blocks,a.clustering_factor from user_indexes a, user_tables b
where index_name in ('xx1','xx2') and a.table_name = b.table_name;
其中clustering_factor:聚簇因子 index_name索引名 num_rows:行數(shù) blocks:數(shù)據(jù)塊where index_name in ('xx1','xx2') and a.table_name = b.table_name;
如果clustering_factor非常接近blocks,說(shuō)明數(shù)據(jù)非常有序,連續(xù)的數(shù)據(jù)可能在一個(gè)塊中,這樣進(jìn)行區(qū)間段等大數(shù)據(jù)查詢的時(shí)候,性能越高
如果clustering_factor非常接近num_rows,說(shuō)明數(shù)據(jù)非常隨即。索引條目指向的數(shù)據(jù)不一定在一個(gè)快中,進(jìn)行區(qū)間等查詢的時(shí)候,性能很差
B*樹索引應(yīng)用場(chǎng)合:1 僅僅返回少數(shù)數(shù)據(jù),數(shù)據(jù)重復(fù)度低;2 直接用索引能完成,沒(méi)有涉及到表(比如select count(x) where x='xx',這種語(yǔ)句直接檢索索引,根本接觸不到表本身,速度顯然很快)
2 位圖索引:對(duì)于頻繁更新的表,不適合建立位圖索引;位圖索引會(huì)記錄該列的數(shù)據(jù)1存放在1,3,4,7...行,數(shù)據(jù)2存放在2,5,6...行,數(shù)據(jù)null存放在8,9...行等等,會(huì)把所有數(shù)據(jù)及其位置都記錄下來(lái);
所以,數(shù)據(jù)的重復(fù)度越高,越適合位圖索引;如何衡量呢,就是不同相數(shù)據(jù)的個(gè)數(shù)除以總行數(shù)越接近零越好;偽代碼:count(distinct(col))/count(*)越接近零,越適合做位圖索引;
以上數(shù)據(jù)不應(yīng)該建立B*樹索引,因?yàn)锽*樹是樹形結(jié)構(gòu),而重復(fù)度高的數(shù)據(jù),會(huì)根據(jù)一個(gè)值檢索到大量的數(shù)據(jù)。這違背了b*樹索引的原則。
如果進(jìn)行查詢select count(*) from Table1 where col1='x' or col1='y',這個(gè)就會(huì)用到位圖索引,只是將2個(gè)合并,都不會(huì)去查詢表,在索引中直接返回正確結(jié)果
如果進(jìn)行查詢select * from table1 wwhere col1='x' or col1='y',這個(gè)會(huì)用到位圖索引,oracle會(huì)到位圖索引去找到所有x和y的索引,然后找到相應(yīng)的rowid,然后根據(jù)rowid快速返回結(jié)果集
對(duì)于頻繁更新的表,為什么不適合用位圖索引:一個(gè)位圖索引中維護(hù)了一個(gè)數(shù)據(jù)和多個(gè)行的位置,如果一個(gè)會(huì)話修改了該列某一行的指定數(shù)據(jù),比如xx1,那么該位圖索引所維護(hù)的xx1數(shù)據(jù)的所有行都會(huì)被鎖定;oracle是無(wú)法鎖定一個(gè)位圖索引中的某一個(gè)行的。這樣就會(huì)出現(xiàn)如下問(wèn)題:
如果該數(shù)據(jù)有100行,那么更新一行的時(shí)候,100行數(shù)據(jù)均被鎖定,導(dǎo)致其他會(huì)話只能等待期釋放之后才能操作;如果頻繁出現(xiàn)這種情況的話,性能會(huì)嚴(yán)重下降。
3 位圖聯(lián)結(jié)索引:這是oracle9i所引入的一個(gè)索引;對(duì)于關(guān)聯(lián)表建立位圖索引,比如有一個(gè)部門表和員工表,員工表中存放了部門表的主鍵,此時(shí)想根據(jù)部門的name來(lái)查詢所有的員工,這是如果建立和位圖聯(lián)結(jié)索引,聚會(huì)很快得到結(jié)果集;
4 基于函數(shù)的索引(待續(xù))
關(guān)于索引常見的問(wèn)題:
1 視圖能建立索引嗎:視圖引用的是基本表,只需要對(duì)基本表建立索引,就相當(dāng)于在視圖中建立索引;
2 Null和索引的協(xié)作:
-- B*樹索引不能建立在都可以為null的列上,因?yàn)锽*書索引會(huì)過(guò)濾掉null,也就是說(shuō),當(dāng)進(jìn)行查詢的時(shí)候:
比如在col1和col2上建立了索引,col1和col2都可以為空,查詢select * from table1 where col1 is null 這個(gè)語(yǔ)句不會(huì)使用索引,因?yàn)槿绻褂盟饕脑挘赡軙?huì)丟失數(shù)據(jù)(那些null的數(shù)據(jù)會(huì)丟失);因?yàn)樗饕裏o(wú)法建立在都可以為null的列上,oracle優(yōu)化器會(huì)選擇不使用索引,而是全表掃描;
3 外鍵是否可以建立索引:在以下情況中,最好在外鍵上建索引
a 如果經(jīng)常進(jìn)行聯(lián)機(jī)刪除或者修改父表主鍵的情況,建議在子表外鍵上建立索引。如果不建立索引的話,有上述操作時(shí),oracle會(huì)把整個(gè)子表全部鎖死,這也是oracle出現(xiàn)死鎖的情況,嚴(yán)重影響系統(tǒng)性能;
b 從父表查詢子表信息的時(shí)候,比如根據(jù)deptName查詢?cè)摬块T下所有員工信息的時(shí)候,建議在子表外鍵上建立索引,或者建立位圖聯(lián)結(jié)索引,否則如果頻繁進(jìn)行上述查詢的話,速度會(huì)很慢,因?yàn)槊看味紝?duì)員工表進(jìn)行了全表掃描。
4 索引為何失效
a 關(guān)于B*樹索引,如果是a、b兩列建立索引,如果a、b兩列都允許為空的話,由于在全是null的數(shù)據(jù)上不會(huì)建立索引,所以為了避免查詢數(shù)據(jù)不準(zhǔn)確,優(yōu)化器會(huì)放棄使用索引,而是使用全表掃描;
b 關(guān)于B*樹索引,如果是a、b兩列建立索引,如果這樣select * from table1 where b =5;此時(shí)如果a列的數(shù)據(jù)重復(fù)率不高的話,如果用索引的話,會(huì)去檢索每條索引的數(shù)據(jù),這樣優(yōu)化器更傾向于用全表掃描;如果a數(shù)據(jù)重復(fù)度很高,優(yōu)化器會(huì)用一種跳躍式掃描方式,此時(shí)會(huì)用上索引;
c 如果用到了函數(shù),比如select * from table1 where f(a) = xx;此時(shí)不會(huì)用到索引,因?yàn)樗饕墙⒃赼上的,而不是建立在f(a)上的;
d 如果a列是字符類型,但是我們執(zhí)行了select * from table1 where a = 5;此時(shí)其實(shí)是隱式的應(yīng)用了to_number(a)=5;索引是建立在a上,而不是建立在函數(shù)上的;
e 有些時(shí)候oracle的優(yōu)化器會(huì)智能的判斷使用索引后是否會(huì)提高效率,如果不會(huì)提高效率那么優(yōu)化器會(huì)自動(dòng)放棄索引,而執(zhí)行full table;此時(shí)請(qǐng)檢查索引的合理性;
oracle編程藝術(shù)上說(shuō):歸根結(jié)底,原因通常就是
“不能使用索引,使用索引會(huì)返回不正確的結(jié)果”
“不應(yīng)該使用索引,使用了,性能會(huì)變得很糟糕”
另外:如果是兩個(gè)列建立索引,那么哪個(gè)放前面,哪個(gè)放后面呢:
這個(gè)要視情況而定,如果只有如下查詢select * from table1 where a= :x and b= :y,那么哪個(gè)在前面都無(wú)所謂;
如果還有這種方式:select * from table1 where b = :y ,那么需要b列在前面;
oracle編程藝術(shù)中還就索引壓縮做出對(duì)比,這里不記錄了。以上都是個(gè)人理解記錄,都是為了方便自己。