天天看點

Oracle資料庫中索引的維護

本文隻讨論Oracle中最常見的索引,即是B-tree索引。本文中涉及的資料庫版本是Oracle8i。

  <b>一. 檢視系統表中的使用者索引</b>

  在Oracle中,SYSTEM表是安裝資料庫時自動建立的,它包含資料庫的全部資料字典,存儲過程、包、函數和觸發器的定義以及系統復原段。

  一般來說,應該盡量避免在SYSTEM表中存儲非SYSTEM使用者的對象。因為這樣會帶來資料庫維護和管理的很多問題。一旦SYSTEM表損壞了,隻能重新生成資料庫。我們可以用下面的語句來檢查在SYSTEM表内有沒有其他使用者的索引存在。

select count(*) 

from dba_indexes

where tablespace_name = 'SYSTEM'

and owner not in ('SYS','SYSTEM')

/

  <b>二. 索引的存儲情況檢查</b>

  Oracle為資料庫中的所有資料配置設定邏輯結構空間。資料庫空間的機關是資料塊(block)、範圍(extent)和段(segment)。

  Oracle資料塊(block)是Oracle使用和配置設定的最小存儲機關。它是由資料庫建立時設定的DB_BLOCK_SIZE決定的。一旦資料庫生成了,資料塊的大小不能改變。要想改變隻能重建立立資料庫。(在Oracle9i中有一些不同,不過這不在本文讨論的範圍内。)

  Extent是由一組連續的block組成的。一個或多個extent組成一個segment。當一個segment中的所有空間被用完時,Oracle為它配置設定一個新的extent。

  

  Segment是由一個或多個extent組成的。它包含某表空間中特定邏輯存儲結構的所有資料。一個段中的extent可以是不連續的,甚至可以在不同的資料檔案中。

  一個object隻能對應于一個邏輯存儲的segment,我們通過檢視該segment中的extent,可以看出相應object的存儲情況。

  (1)檢視索引段中extent的數量:

select segment_name, count(*) 

from dba_extents

where segment_type='INDEX'

and owner=UPPER('&amp;owner') 

group by segment_name

  (2)檢視表空間内的索引的擴充情況:

select

substr(segment_name,1,20) "SEGMENT NAME",

bytes, 

count(bytes) 

from dba_extents 

where segment_name in

( select index_name 

from dba_indexes 

where tablespace_name=UPPER('&amp;表空間'))

group by segment_name,bytes

order by segment_name

三. 索引的選擇性

  索引的選擇性是指索引列中不同值的數目與表中記錄數的比。如果一個表中有2000條記錄,表索引列有1980個不同的值,那麼這個索引的選擇性就是1980/2000=0.99。

  一個索引的選擇性越接近于1,這個索引的效率就越高。

  如果是使用基于cost的最優化,優化器不應該使用選擇性不好的索引。如果是使用基于rule的最優化,優化器在确定執行路徑時不會考慮索引的選擇性(除非是唯一性索引),并且不得不手工優化查詢以避免使用非選擇性的索引。

  确定索引的選擇性,可以有兩種方法:手工測量和自動測量。

  (1)手工測量索引的選擇性

  如果要根據一個表的兩列建立兩列并置索引,可以用以下方法測量索引的選擇性:

  列的選擇性=不同值的數目/行的總數 /* 越接近1越好 */

select count(distinct 第一列||'%'||第二列)/count(*)

from 表名

  如果我們知道其中一列索引的選擇性(例如其中一列是主鍵),那麼我們就可以知道另一列索引的選擇性。

  手工方法的優點是在建立索引前就能評估索引的選擇性。

  (2)自動測量索引的選擇性

  如果分析一個表,也會自動分析所有表的索引。

  第一,為了确定一個表的确定性,就要分析表。

analyze table 表名 

compute statistics

  第二,确定索引裡不同關鍵字的數目:

select distinct_keys

from user_indexes

where table_name='表名'

and index_name='索引名'

  第三,确定表中行的總數:

select num_rows

from user_tables

  第四,索引的選擇性=索引裡不同關鍵字的數目/表中行的總數:

select i.distinct_keys/t.num_rows

from

user_indexes i,

user_tables t

where i.table_name='表名'

and i.index_name='索引名'

and i.table_name=t.table_name

  第五,可以查詢USER_TAB_COLUMNS以了解每個列的選擇性。

  表中所有行在該列的不同值的數目:

column_name,

num_distinct

from user_tab_columns

  列的選擇性=NUM_DISTINCT/表中所有行的總數,查詢USER_TAB_COLUMNS有助測量每個列的選擇性,但它并不能精确地測量列的并置組合的選擇性。要想測量一組列的選擇性,需要采用手工方法或者根據這組列建立一個索引并重新分析表。

  <b>四. 确定索引的實際碎片</b>

  随着資料庫的使用,不可避免地對基本表進行插入,更新和删除,這樣導緻葉子行在索引中被删除,使該索引産生碎片。插入删除越頻繁的表,索引碎片的程度也越高。碎片的産生使通路和使用該索引的I/O成本增加。碎片較高的索引必須重建以保持最佳性能。

  (1)利用驗證索引指令對索引進行驗證。

  這将有價值的索引資訊填入index_stats表。

validate index 使用者名.索引名

  (2)查詢index_stats表以确定索引中删除的、未填滿的葉子行的百分比。

name,

del_lf_rows,

lf_rows,

round((del_lf_rows/(lf_rows+0.0000000001))*100) "Frag Percent"

from index_stats

  (3)如果索引的葉子行的碎片超過10%,考慮對索引進行重建。

alter index 使用者名.索引名 rebuild

tablespace 表空間名

storage(initial 初始值 next 擴充值)

nologging

  (4)如果出于空間或其他考慮,不能重建索引,可以整理索引。

alter index使用者名.索引名 coalesce

  (5)清除分析資訊

analyze index 使用者名.索引名

delete statistics

五. 重建索引

  (1)檢查需要重建的索引。

  根據以下幾方面進行檢查,确定需要重建的索引。

  第一,檢視SYSTEM表空間中的使用者索引。

  為了避免資料字典的碎片出現,要盡量避免在SYSTEM表空間出現使用者的表和索引。

select index_name 

where tablespace_name='SYSTEM' 

  第二,確定使用者的表和索引不在同一表空間内。

  表和索引對象的第一個規則是把表和索引分離。把表和相應的索引建立在不同的表空間中,最好在不同的磁盤上。這樣可以避免在資料管理和查詢時出現的許多I/O沖突。

set linesize 120

col "OWNER" format a20

col "INDEX" format a30

col "TABLE" format a30

col "TABLESPACE" format a30

i.owner "OWNER", 

i.index_name "INDEX",

t.table_name "TABLE",

i.tablespace_name "TABLESPACE"

from 

dba_indexes i,

dba_tables t

where i.owner=t.owner

and i.tablespace_name=t.tablespace_name

and i.owner not in ('SYS','SYSTEM')

  第三,檢視資料表空間裡有哪些索引

  使用者的預設表空間應該不是SYSTEM表空間,而是資料表空間。在建立索引時,如果不指定相應的索引表空間名,那麼,該索引就會建立在資料表空間中。這是程式員經常忽略的一個問題。應該在建索引時,明确的指明相應的索引表空間。

col segment_name format a30

select 

owner,

segment_name,

sum(bytes) 

from dba_segments

where tablespace_name='資料表空間名'

and segment_type='INDEX'

group by owner,segment_name

  第四,檢視哪個索引被擴充了超過10次

  随着表記錄的增加,相應的索引也要增加。如果一個索引的next extent值設定不合理(太小),索引段的擴充變得很頻繁。索引的extent太多,檢索時的速度和效率就會降低。

set linesize 100

col owner format a10

col tablespace_name format a30

count(*),

tablespace_name

group by owner,segment_name,tablespace_name

having count(*) &gt;10

order by count(*) desc

  (2)找出需要重建的索引後,需要确定索引的大小,以設定合理的索引存儲參數。

col "TABLESPACE" format a20

owner "OWNER",

segment_name "INDEX",

tablespace_name "TABLESPACE",

bytes "BYTES/COUNT",

sum(bytes) "TOTAL BYTES",

round(sum(bytes)/(1024*1024),0) "TOTAL M",

count(bytes) "TOTAL COUNT"

where segment_type='INDEX' 

and segment_name in 

(

'索引名1',

'索引名2',

......

)

group by owner,segment_name,segment_type,tablespace_name,bytes

order by owner,segment_name

  (3)确定索引表空間還有足夠的剩餘空間。

  确定要把索引重建到哪個索引表空間中。要保證相應的索引表空間有足夠的剩餘空間。

select round(bytes/(1024*1024),2) free(M)

from sm$ts_free

where tablespace_name='表空間名'

  (4)重建索引。

  重建索引時要注意以下幾點:

  a.如果不指定tablespace名,索引将建在使用者的預設表空間。

  b.如果不指定nologging,将會寫日志,導緻速度變慢。由于索引的重建沒有恢複的必要,是以,可以不寫日志。

  c.如果出現資源忙,表明有程序正在使用該索引,等待一會再送出。

alter index 索引名

rebuild

tablespace 索引表空間名

  (5)檢查索引。

  對重建好的索引進行檢查。

select *

where segment_name='索引名'

  (6)根據索引進行查詢,檢查索引是否有效

  使用相應的where條件進行查詢,確定使用該索引。看看使用索引後的效果如何。

from dba_ind_columns

where index_name like '表名%'

  然後,根據相應的索引項進行查詢。

from '表名%'

where ......

  (6)找出有碎片的表空間,并收集其碎片。

  重建索引後,原有的索引被删除,這樣會造成表空間的碎片。

select 'alter tablespace '||tablespace_name||' coalesce;'

from dba_free_space_coalesced

where percent_blocks_coalesced!=100

  整理表空間的碎片。

alter tablespace 表空間名 coalesce

本文轉自斯克迪亞部落格園部落格,原文連結http://www.cnblogs.com/sgsoft/archive/2004/10/12/51135.html,如需轉載請自行聯系原作者