Oracle 索引的維護

lygle發表於2013-03-26

一.檢視系統表中的使用者索引
Oracle中,SYSTEM表是安裝資料庫時自動建立的,它包含資料庫的全部資料字典,儲存過程、包、函式和觸發器的定義以及系統回滾段。
一般來說,應該儘量避免在SYSTEM表中儲存非SYSTEM使用者的物件。因為這樣會帶來資料庫維護和管理的很多問題。一旦SYSTEM表損壞了,只能重新生成資料庫。我們可以用下面的語句來檢查在SYSTEM表內有沒有其他使用者的索引存在。

/* Formatted on 2010/6/19 13:22:46 (QP5 v5.115.810.9015) */

SELECT *

FROM dba_indexes

WHERE tablespace_name = 'SYSTEM' AND owner NOT IN ('SYS', 'SYSTEM')


. 索引的儲存情況檢查
Oracle為資料庫中的所有資料分配邏輯結構空間。資料庫空間的單位是blockextentsegment

BlockOracle使用和分配的最小儲存單位。它是由資料庫建立時設定的DB_BLOCK_SIZE決定的。一旦資料庫生成了,資料塊的大小不能改變。要想改變只能重新建立資料庫。

Extent是由一組連續的block組成的。一個或多個extent組成一個segment。當一個segment中的所有空間被用完時,Oracle為它分配一個新的extent
Segment是由一個或多個extent組成的。它包含某表空間中特定邏輯儲存結構的所有資料。一個段中的extent可以是不連續的,甚至可以在不同的資料檔案中。

 

一個object只能對應於一個邏輯儲存的segment,我們通過檢視該segment中的extent,可以看出相應object的儲存情況。
1)檢視索引段中extent的數量:
/* Formatted on 2010/6/19 13:47:34 (QP5 v5.115.810.9015) */

SELECT segment_name, COUNT ( * )

FROM dba_extents

WHERE segment_type = 'INDEX' AND owner = UPPER ('NEWCCS')

GROUP BY segment_name


2)檢視錶空間內的索引的擴充套件情況:

/* Formatted on 2010/6/19 14:05:23 (QP5 v5.115.810.9015) */

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 ('NEWCCS'))

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 where table_name="表名"
第四索引的選擇性=索引裡不同關鍵字的數目/表中行的總數
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以瞭解每個列的選擇性
表中所有行在該列的不同值的數目:
select column_name, num_distinct from user_tab_columns where table_name="表名"

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


. 確定索引的實際碎片
隨著資料庫的使用,不可避免地對基本表進行插入,更新和刪除,這樣導致葉子行在索引中被刪除,使該索引產生碎片。插入刪除越頻繁的表,索引碎片的程度也越高。碎片的產生使訪問和使用該索引的I/O成本增加。碎片較高的索引必須重建以保持最佳效能。


1)利用驗證索引命令對索引進行驗證。
這將有價值的索引資訊填入index_stats表。
validate index 使用者名稱.索引名

或者:

analyze index index_name validate structure;

注意:index_stats只儲存最近一次分析的結果


2)查詢index_stats表以確定索引中刪除的、未填滿的葉子Leaf行的百分比height 欄位
select name,height, del_lf_rows, lf_rows, round((del_lf_rows/(lf_rows+0.0000000001))*100) "Frag Percent" from index_stats


3)如果索引的葉子行的碎片超過10%或者 index_statsheight > =4, 可以考慮對索引進行重建。
alter index 使用者名稱.索引名 rebuild tablespace 表空間名 storage(initial 初始值 next 擴充套件值) nologging

參考:如何加快建 index 索引 的時間

http://blog.csdn.net/tianlesoftware/archive/2010/06/11/5664019.aspx

DBA1群裡 長沙-Rourk33 同學提供的指令碼, 可以一次生成擴充套件大於10次的索引的指令碼。感謝Rourk33 同學。

/* Formatted on 2010/6/19 21:58:45 (QP5 v5.115.810.9015) */

SELECT 'alter index ' || owner || '.' || segment_name || ' rebuild;'

FROM ( SELECT COUNT ( * ),

owner,

segment_name,

t.tablespace_name

FROM dba_extents t

WHERE t.segment_type = 'INDEX'

AND t.owner NOT IN ('SYS', 'SYSTEM')

GROUP BY owner, segment_name, t.tablespace_name

HAVING COUNT ( * ) > 10

ORDER BY COUNT ( * ) DESC);


4)如果出於空間或其他考慮,不能重建索引,可以整理索引。
alter index使用者名稱.索引名 coalesce


5)清除分析資訊
analyze index 使用者名稱.索引名 delete statistics

 


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

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

select index_name from dba_indexes where tablespace_name="SYSTEM" and owner not in ("SYS","SYSTEM")


第二,確保使用者的表和索引不在同一表空間內
表和索引物件的第一個規則是把表和索引分離。把表和相應的索引建立在不同的表空間中,最好在不同的磁碟上。這樣可以避免在資料管理和查詢時出現的許多I/O衝突。

/* Formatted on 2010/6/19 21:00:08 (QP5 v5.115.810.9015) */

SELECT 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.table_name = t.table_name

AND i.tablespace_name = t.tablespace_name

AND i.owner NOT IN ('SYS', 'SYSTEM')


第三,檢視資料表空間裡有哪些索引
使用者的預設表空間應該不是SYSTEM表空間,而是資料表空間。在建立索引時,如果不指定相應的索引表空間名,那麼,該索引就會建立在資料表空間中。這是程式設計師經常忽略的一個問題。應該在建索引時,明確的指明相應的索引表空間。

/* Formatted on 2010/6/19 21:05:01 (QP5 v5.115.810.9015) */

SELECT owner, segment_name, SUM (bytes)

FROM dba_segments

WHERE tablespace_name ='SYSTEM' AND segment_type = 'INDEX'

GROUP BY owner, segment_name


第四,檢視哪個索引被擴充套件了超過10
隨著表記錄的增加,相應的索引也要增加。如果一個索引的next extent值設定不合理(太小),索引段的擴充套件變得很頻繁。索引的extent太多,檢索時的速度和效率就會降低。

1) 檢視索引擴充套件次數

/* Formatted on 2010/6/19 21:13:41 (QP5 v5.115.810.9015) */

SELECT COUNT ( * ),

owner,

segment_name,

tablespace_name

FROM dba_extents

WHERE segment_type = 'INDEX' AND owner NOT IN ('SYS', 'SYSTEM')

GROUP BY owner, segment_name, tablespace_name

HAVING COUNT ( * ) > 10

ORDER BY COUNT ( * ) DESC


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

/* Formatted on 2010/6/19 21:19:32 (QP5 v5.115.810.9015) */

SELECT 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"

FROM dba_extents

WHERE segment_type = 'INDEX'

AND segment_name IN ('INDEX_NAME1', 'INDEX_NAME2')

GROUP BY owner,

segment_name,

segment_type,

tablespace_name,

bytes

ORDER BY owner, segment_name

3確定索引表空間還有足夠的剩餘空間
確定要把索引重建到哪個索引表空間中。要保證相應的索引表空間有足夠的剩餘空間。
/* Formatted on 2010/6/19 21:27:50 (QP5 v5.115.810.9015) */

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 索引表空間名 storage(initial 初始值 next 擴充套件值) nologging


5)檢查索引
對重建好的索引進行檢查。
select * from dba_extents where segment_name="索引名"

6)根據索引進行查詢,檢查索引是否有效
使用相應的where條件進行查詢,確保使用該索引。看看使用索引後的效果如何。
select * from dba_ind_columns where index_name='索引名'

然後,根據相應的索引項進行查詢。
select * from "表名" where ...


7)找出有碎片的表空間,並收集其碎片。
重建索引後,原有的索引被刪除,這樣會造成表空間的碎片。

/* Formatted on 2010/6/19 21:40:45 (QP5 v5.115.810.9015) */

SELECT 'alter tablespace ' || tablespace_name || ' coalesce;'

FROM dba_free_space_coalesced

WHERE percent_blocks_coalesced != 100

檢視索引佔用空間大小:

select (sum(bytes)/1024/1024)||'MB' from dba_segments where segment_name = 'INDBILLLOG5_CALLEND';

檢視錶佔用空間大小

select (sum(bytes)/1024/1024)||'MB' from dba_segments where segment_name = 'TBILLLOG5';

注: 整理自網路

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/28673746/viewspace-757134/,如需轉載,請註明出處,否則將追究法律責任。

相關文章