索引由 Oracle 服務器自動使用和維護,一旦一個索引被創建,它就不再需要用戶直接管理。rowid是一個十六進制的串,表示包含塊定義的行地址,行的位置在塊中,並且有數據庫文件標識符,訪問任何指定行的最快的方法是引用它的 rowid.
索引里存儲的內容: ROWID 、索引列(鍵值)。
創建索引可以大大提高系統的性能,總體來說,索引的優點如下所示:
- 大大加快數據的檢索速度,這也是創建索引的最主要的原因。
- 索引可以加速表和表之間的連接。
- 索引在實現數據的參照完整性方面特別有意義,例如在外鍵列上創建索引可以有效的避免死鎖的發生,
- 也可以防止當更新父表主鍵時,數據庫對子表的全表鎖定。
- 索引是減少磁盤 I/O 的許多有效手段之一。
- 當使用分組(GROUP BY)和排序(ORDER BY)子句進行數據檢索時,可以顯著減少查詢中分組和排序的時間,大大加快數據的檢索速度。
- 創建唯一性索引,可以保證數據庫表中每一行數據的唯一性。
- 通過使用索引,可以在查詢的過程中,使用優化隱藏器,提高系統的性能。
索引的缺點如下所示:
- 索引必須創建在表上,不能創建在視圖上。
- 創建索引和維護索引要耗費時間,這種時間隨着數據量的增加而增加。
- 建立索引需要占用物理空間,如果要建立聚簇索引,那么需要的空間會很大。
- 當對表中的數據進行增加、刪除和修改的時候,系統必須要有額外的時間來同時對索引進行更新維護,以維持數據和索引的一致性,所以,索引降低了數據的維護速度
索引的使用原則:
- 在大表上建立索引才有意義。
- 在 WHERE 子句或是連接條件經常引用的列上建立索引。
- 索引的層次不要超過 4 層。
- 如果某屬性常作為最大值和最小值等聚集函數的參數,那么考慮為該屬性建立索引。
- 表的主鍵、外鍵必須有索引
- 創建了主鍵和唯一約束后會自動創建唯一索引。
- 經常與其它表進行連接的表,在連接字段上應該建立索引。
- 經常出現在 WHERE 子句中的字段,特別是大表的字段,應該建立索引。
- 要索引的列經常被查詢,並只返回表中的行的總數的一小部分。
- 對於那些查詢中很少涉及的列、重復值比較多的列盡量不要建立索引。
- 經常出現在關鍵字 ORDER BY、GROUP BY、DISTINCT 后面的字段,最好建立索引。
- 索引應該建在選擇性高的字段上。
- 索引應該建在小字段上,對於大的文本字段甚至超長字段,不適合建索引。對於定義為 CLOB、TEXT、IMAGE 和 BIT 的數據類型的列不適合建立索引。
- 復合索引的建立需要進行仔細分析。正確選擇復合索引中的前導列字段,一般是選擇性較好的字段。
- 如果單字段查詢很少甚至沒有,那么可以建立復合索引;否則考慮單字段索引。
- 如果復合索引中包含的字段經常單獨出現在 WHERE 子句中,那么分解為多個單字段索引。
- 如果復合索引所包含的字段超過 3 個,那么仔細考慮其必要性,考慮減少復合的字段。
- 如果既有單字段索引,又有這幾個字段上的復合索引,那么一般可以刪除復合索引。
- 頻繁進行 DML 操作的表,不要建立太多的索引。
- 刪除無用的索引,避免對執行計划造成負面影響
一個表中定義一個列為主鍵,或者定義一個唯一鍵約束時 Oracle 服務器自動創建該索引,索引的名字習慣上是約束的名字
另外,需要特別注意的是,索引不存儲空值。
為什么不走索引(339頁詳解)
位圖索引
- 適合於決策支持系統(DSS)或 OLAP 系統。位圖索引主要用於數據倉庫,或在以特定方式引用很多列的查詢環境中。位圖索引並不適合許多 OLTP 應用程序,若使用不當則容易產生死鎖。
- 被索引的表是只讀的,或 DML 語句不會對其進行頻繁修改的表。
- 非常適合 OR 操作符的查詢。
- 位圖索引不直接存儲 ROWID,而是存儲字節位到 ROWID 的映射。
- 減少響應時間。
- 節省空間占用。
- 在同一列上建立位圖索引后就不能再建立普通索引了,但是可以建立函數索引,位圖索引可以和函數索引同時建立。
- 做 UPDATE 代價非常高。
- 基於規則的優化器不會考慮位圖索引。
- 當執行 ALTER TABLE 語句並修改包含有位圖索引的列時,會使位圖索引失效。
- 位圖索引不包含任何列數據,並且不能用於任何類型的完整性檢查。
- 位圖索引不能被聲明為唯一索引。
- 位圖索引的最大長度為 30。
- 位圖索引適合創建在低基數列(即列值重復率很高)上。
函數索引
創建索引的函數里面不能使用 SUM、COUNT 等聚合函數
不能在 LOB 類型的列、NESTED TABLE 列上創建函數索引。
不能使用 SYSDATE、USER 等非確定性函數。
對於任何用戶自定義函數必須顯式的聲明 DETERMINISTIC 關鍵字,否則會報錯:“ora-30553: thefunction is not deterministic”
使用函數索引有幾個先決條件:
(1)必須擁有 CREATE INDEX 和 QUERY REWRITE(本模式下)或 CREATE ANY INDEX 和 GLOBAL QUERY REWRITE(其它模式下)權限。
(2)必須使用基於成本的優化器,基於規則的優化器將被忽略。
(3)參數 QUERY_REWRITE_INTEGRITY 和 QUERY_REWRITE_ENABLED 可以保持默認值
索引組織表(IOT)
索引中存儲的是行的實際數據,而不是 ROWID,它是基於主鍵訪問數據的。在索引組織表中,索引就是數據,數據就是索引
輔助索引(Secondary Indexes)也叫二級索引,是一個建立在索引組織表上的索引。在某種意義上,它是一個索引的索引。輔助索引是一個獨立的模式對象,並與索引組織表分開存儲。索引表上的輔助索引能夠非常有效地訪問索引表,這種索引既不是使用主鍵列也不是使用主鍵的某個前綴。Oracle 構造這種索引使用的是邏輯的行標識符(Logical Rowids),這種 ROWIDS 是基於表的主鍵(而不是基於行的物理地址)。這種邏輯 ROWIDS 包括了一個物理猜想(Physical Guess),它也是一種物理標識符(物理指針),它唯一標識行的塊地址,Oracle 能使用這些猜想直接對索引表的葉塊進行探測,從而避免主鍵搜索。
當創建 IOT 時,必須要設定主鍵,否則報錯。
分區索引
如果使用了位圖索引,那么就必須是本地索引
本地分區索引可分為以下類別:
- 本地前綴索引(Local Prefixed Indexes)在這種情況下,分區鍵處於索引定義的前導部分。
- 本地非前綴索引(Local Nonprefixed Indexes)在這種情況下,分區鍵不是索引列列表的前導部分,甚至根本不必在該列表中。
CREATE INDEX IDX_PART_RANGE_ID ON T_PARTITION_RANGE(ID) LOCAL (
PARTITION I_RANGE_P1 TABLESPACE TS_DATA01,
PARTITION I_RANGE_P2 TABLESPACE TS_DATA02,
PARTITION I_RANGE_P3 TABLESPACE TS_DATA03,
PARTITION I_RANGE_PMAX TABLESPACE TS_DATA04
);
全局分區索引是一個 B-Tree 索引,全局索引(Global Index)既可以分區(全局分區索引),也可以不分區(普通索引),既可以建 RANGE分區,也可以建 HASH 分區,既可創建於分區表上,也可以創建於非分區表上,就是說,全局索引是完全獨立的,因此,它也需要更多的維護操作
- 全局索引可以依附於分區表,也可以依附於非分區表。
- 全局分區索引的索引條目可能指向若干個分區,因此,對於全局分區索引,即使只截斷一個分區中的數據,也需要 REBULID 若干個分區甚至是整個索引。
- 全局索引多應用於 OLTP 系統中。
- 全局分區索引只按 RANGE 或者 HASH 分區,HASH 分區是 Oracle 10g 以后才支持的。
- 在 Oracle 9i 以后對分區表做 MOVE 或者 TRUNCATE 的時候可以用 UPDATE GLOBAL INDEXES 語句來同步更新全局分區索引,用消耗一定資源來換取高度的可用性。
- 若在表中使用 A 列作分區,但在索引中用 B 列作本地索引,若 WHERE 條件中用 B 來查詢,那么 Oracle會掃描所有的表和索引的分區,成本會比分區更高,此時可以考慮用 B 列做全局分區索引和用 A 列做本地索引。
- 在創建索引時,如果不顯式指定 GLOBAL 或 LOCAL,那么默認是 GLOBAL。
- 在創建 GLOBAL 索引時,如果不顯式指定分區子句,那么默認不分區。
- 含有子分區的分區索引有大小,但是在數據字典視圖中的列 SEGMENT_CREATED 的值顯示為 N/A,STATUS 的值也顯示為 N/A。
Truncate 分區操作會導致全局索引失效; truncate 普通表對索引沒有影響;
Truncate 分區操作不會釋放全局索引中的空間,而truncate 普通表會釋放索引所占空間;
rename 表名操作對索引沒有影響,因為rename操作只是更改了數據字典,表中數據行的rowid並沒有發生變化
全文索引
Oracle 全文索引使 Oracle 具備了強大的文本檢索能力和智能化的文本管理能力。Oracle 將全文檢索功能做為內置功能提供給用戶,使得用戶在創建數據庫實例時自動安裝全文檢索。要使用 Oracle 全文索引,必須具有 CTXAPP 角色或者是 CTXSYS 用戶。Oracle 全文索引為系統管理員提供 CTXSYS 用戶,為應用程序開發人員提供 CTXAPP 角色。具有 CTXAPP 角色的用戶可以使用全文索引
虛擬索引
不可見索引
ALTER INDEX INDEX_NAME INVISIBLE; --修改索引不可見
ALTER INDEX INDEX_NAME VISIBLE; --修改索引可見
不可見索引的特點主要有以下幾點:
(1)當索引變更為不可見的時候,只是對 Oracle 的優化器不可見。
(2)不可見索引在 DML 操作的時候也會被維護。
(3)加 HNIT 對不可見索引無效。
(4)可以通過修改 SYSTEM 級別和 SESSION 級別參數來使用不可見索引。
反向鍵索引(Reverse Key Indexes)
只有對反向鍵索引列進行“=”操作時,其反向鍵索引才會使用。(在 WHERE 子句中使用“BETWEEN AND”語句或比較運算符“>”、“<”、“>=”、“<=”等),那么反向鍵索引將不會被使用
反向鍵索引應用場合:
1、在索引葉塊成為熱點塊時使用
2、在 RAC 環境中使用
3、反向鍵索引通常建立在值是連續增長的列上,使數據均勻地分布在整個索引上。
創建索引
create index emp_last_name_idx on employees(last_name) online parallel 2; ---普通單列索引
CREATE INDEX IDX_CI_emp ON employees(OBJECT_ID,OBJECT_TYPE); ---復合索引(一般情況下,把最常被訪問和選擇性較高的列放在前面)
CREATE INDEX upper_last_name_idx ON employees(UPPER(last_name)); ---函數索引
CREATE BITMAP INDEX IDX_SEX_LHR ON T_USER(SEX); ---創建位圖索引
CREATE TABLE IND_ORG_TAB_LHR(VENCODE NUMBER(4) PRIMARY KEY,VENNAME VARCHAR2(20)) ORGANIZATION INDEX; ---索引組織表
CREATE INDEX DOC_INDEX_LHR ON XT_DOCS_LHR(TEXT) INDEXTYPE IS CTXSYS.CONTEXT; ---創建全文索引
CREATE INDEX REV_INDEX_LHR ON XT_REVI_LHR(OBJECT_ID) REVERSE; ---創建反向鍵索引
DROP INDEX IDX_NAME_LHR FORCE; ---刪除索引
查看索引信息
SELECT IC.INDEX_NAME,IC.COLUMN_NAME,IC.COLUMN_POSITION COL_POS,IX.UNIQUENESS FROM USER_INDEXES IX, USER_IND_COLUMNS IC WHERE IC.INDEX_NAME = IX.INDEX_NAME
AND IC.TABLE_NAME = 'EMPLOYEES'; ---查詢某個表上的索引
SELECT D.INDEX_NAME,D.TABLE_NAME,D.COLUMN_NAME FROM DBA_IND_COLUMNS D WHERE D.INDEX_NAME='IDX_CI_20170628_LHR'; ---查詢復合索引列
SELECT * FROM DBA_INDEXES D WHERE D.INDEX_TYPE LIKE 'FUNCTION-BASED%'; ---查詢所有的函數索引
SELECT * FROM DBA_INDEXES D WHERE D.INDEX_TYPE='BITMAP'; ---查詢所有的位圖索引
SELECT * FROM DBA_INDEXES D WHERE D.JOIN_INDEX='YES'; ---查詢所有的位圖連接索引
SELECT * FROM DBA_TABLES D WHERE D.IOT_TYPE='IOT'; ---查詢所有的IOT表
SELECT * FROM DBA_INDEXES D WHERE D.INDEX_TYPE LIKE '%/REV'; ---查詢反向鍵索引
獲取索引定義
select dbms_metadata.get_ddl('INDEX','INDEX_NAME','INDEX_OWNER') from dual;
索引選擇性
SELECT INDEX_NAME,DISTINCT_KEYS/NUM_ROWS SELECTIVITY FROM DBA_INDEXES; 毋庸置疑,主鍵的選擇性為 1。選擇性越接近 1,那么該索引就越好。
查詢索引大小
select owner,segment_name,(sum(bytes)/1024/1024)||'MB',tablespace_name from dba_segments where segment_name = 'IDX_T' group by owner,segment_name,tablespace_name;
---查詢大索引
col owner for a10
col segment_name for a32
select * from (select owner,segment_name,bytes/1024/1024 SIZE_MB from dba_segments where owner in ('TEST') and segment_type like '%INDEX%' order by 3 desc) where rownum < 11;
Oracle 11gR2 中使用 EXPLAIN PLAN FOR CREATE INDEX 時,Oracle會提示評估的索引大小(ESTIMATED INDEX SIZE)
EXPLAIN PLAN FOR CREATE INDEX IDX_T ON SYS.TEST_INDEX_SIZE(OBJECT_ID); SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY());

查詢索引碎片比例
analyze index ID_IND validate structure; ---下面語句不要在其他會話查詢 select name,del_lf_rows,lf_rows, round(del_lf_rows/decode(lf_rows,0,1,lf_rows)*100,0)||'%' frag_pct from index_stats where round(del_lf_rows/decode(lf_rows,0,1,lf_rows)*100,0)>30;
注意:x$kdxst是oracle的一個內存表,然后analyze index indexname validate structure這條語句會往x$kdxst寫一些統計信息,當執行select * from x$kdxst的時候,oracle這里實際上是把你執行analyze index indexname validate structure時的那個indexname給當作綁定變量給傳進來了,所以你只能看到你執行analyze index indexname validate structure的那個index的統計信息。也就是只有在執行過analyze index indexname validate structure后且在同一個session下才能從index_stats中看到數據
索引失效情況:
當某些操作導致數據行的 ROWID 改變,索引就會完全失效。可以分普通表和分區表來討論哪些操作將導致索引失效。
(1)普通表索引失效的情形如下所示:
1、手動置索引無效:ALTER INDEX IND_OBJECT_ID UNUSABLE;。
2、如果對表進行 MOVE 操作(包含移動表空間和壓縮操作)或在線重定義表后,那么該表上所有的索引狀態會變為 UNUSABLE。MOVE 操作的 SQL 語句為:ALTER TABLE TT MOVE;。
3、SQL*Loader加載數據。在SQL*Loader加載過程中會維護索引,由於數據量比較大,在SQL*Loader加載過程中出現異常情況,也會導致Oracle來不及維護索引,導致索引處於失效狀態,影響查詢和加載。異常情況主要有:在加載過程中殺掉 SQL*Loader 進程、重啟或表空間不足等。
(2)分區表索引失效的情形如下所示:
1、對分區表的某個含有數據的分區執行了 TRUNCATE、DROP 操作可以導致該分區表的全局索引失效,而分區索引依然有效,如果操作的分區沒有數據,那么不會影響索引的狀態。需要注意的是,對分區表的 ADD
操作對分區索引和全局索引沒有影響。
2 執行 EXCHANGE 操作后,全局索引和分區索引都無條件地會被置為 UNUSABLE(無論分區是否含有數據)。但是,若包含 INCLUDING INDEXES 子句(缺省情況下為 EXCLUDING
INDEXES),則全局索引會失效,而分區索引依然有效。
3 如果執行 SPLIT 的目標分區含有數據,那么在執行 SPLIT 操作后,全局索引和分區索引都會被被置為UNUSABLE。如果執行 SPLIT 的目標分區沒有數據,那么不會影響索引的狀態。
4 對分區表執行 MOVE 操作后,全局索引和分區索引都會被置於無效狀態。
5 手動置其無效:ALTER INDEX IND_OBJECT_ID UNUSABLE;。對於分區表而言,除了 ADD 操作之外,TRUNCATE、DROP、EXCHANGE 和 SPLIT 操作均會導致全局索引失
效,但是可以加上 UPDATE GLOBAL INDEXES 子句讓全局索引不失效。重建分區索引的命令為:ALTER INDEX IDX_RANG_LHR REBUILD PARTITION P1;。
列出失效索引或索引分區
select owner, index_name, status From dba_indexes where status='UNUSABLE' and owner in ('FENG') order by 1,2; select index_owner,index_name,partition_name,subpartition_name from dba_ind_subpartitions where status='unusable' and index_owner in('FENG');
重建索引
alter index indexname rebuild online tablespace t1;
alter index indexname rebuild partition paritionname tablespace tablespacename; alter index indexname rebuild subpartition partitioname tablespace tablespacename;
alter index index_name coalesce
1、rebuild以index fast full scan(or table full scan) 方式讀取原索引中的數據來構建一個新的索引,有排序的操作; rebuild online 執行表掃描獲取數據,有排序的操作; 2、rebuild 會阻塞 dml 操作 ,rebuild online 不會阻塞 dml 操作; 3、rebuild online 時系統會產生一個 SYS_JOURNAL_xxx 的 IOT 類型的系統臨時日志表,所有 rebuild online 時索引的變化都記錄在這個表中,當新的索引創建完成后,把這個表的記錄維護到新的索引中去,然后 drop 掉舊的索引 4、Rebuild操作會產生大量redo log;
5、使用帶有coalesce參數時重建期間不需要額外空間,它只是在重建索引時將處於同一個索引分支內的葉塊拼合起來,這最大限度的減少了與查詢過程中相關的潛在的加鎖問題,但是,coalesce選項不能用來將一個索引轉移到其他表空間。
監控索引使用情況
監控索引一般有兩種方式:
1)直接監控索引的使用情況
(1)設置所要監控的索引:ALTER INDEX IDX_T_XX MONITORING USAGE;
(2)查看該索引有沒有被使用:SELECT * FROM V$OBJECT_USAGE;
(3)關閉監控:ALTER INDEX IDX_T_XX NOMONITORING USAGE;
2)schema級別索引監控
如果想在系統中監控所有的索引,可以通過下面腳本實現監控數據庫所有的索引。注意我們要排除一些系統表的索引、以及LOB indexes。可以直接執行腳本來開啟索引監控,當然監控索引時長非常重要,太短的話有可能導致查詢出來的數據有問題,一般建議監控一周后即可,OLAP系統則需要適當延長監控的時間。
--1、開啟索引監控 SELECT 'ALTER INDEX ' || owner || '.' || index_name || ' MONITORING USAGE;' enable_monitor, 'ALTER INDEX ' || owner || '.' || index_name || ' NOMONITORING USAGE;' disable_monitor FROM dba_indexes WHERE INDEX_TYPE != 'LOB' and owner IN (SELECT username FROM dba_users WHERE account_status = 'OPEN') AND owner NOT IN ('SYS', 'SYSTEM', 'PERFSTAT', 'MGMT_VIEW', 'MONITOR', 'SYSMAN', 'DBSNMP') AND owner not like '%SYS%'; --2、查詢數據庫中所有被監控索引的使用情況 SELECT U.NAME OWNER, IO.NAME INDEX_NAME, T.NAME TABLE_NAME, DECODE(BITAND(I.FLAGS, 65536), 0, 'NO', 'YES') MONITORING, DECODE(BITAND(OU.FLAGS, 1), 0, 'NO', 'YES') USED, OU.START_MONITORING START_MONITORING, OU.END_MONITORING END_MONITORING FROM SYS.USER$ U, SYS.OBJ$ IO, SYS.OBJ$ T, SYS.IND$ I, SYS.OBJECT_USAGE OU WHERE I.OBJ# = OU.OBJ# AND IO.OBJ# = OU.OBJ# AND T.OBJ# = I.BO# AND U.USER# = IO.OWNER#; --3、歷史執行計划分析索引使用情況 WITH TMP1 AS (SELECT I.OWNER INDEX_OWNER, I.TABLE_OWNER, TABLE_NAME, INDEX_NAME, INDEX_TYPE, (SELECT NB.CREATED FROM DBA_OBJECTS NB WHERE NB.OWNER = I.OWNER AND NB.OBJECT_NAME = I.INDEX_NAME AND NB.SUBOBJECT_NAME IS NULL AND NB.OBJECT_TYPE = 'INDEX') CREATED, (SUM(S.BYTES) / 1024 / 1024) INDEX_MB, (SELECT COUNT(1) FROM DBA_IND_COLUMNS DIC WHERE DIC.INDEX_NAME = I.INDEX_NAME AND DIC.TABLE_NAME = I.TABLE_NAME AND DIC.INDEX_OWNER = I.OWNER) COUNT_INDEX_COLS FROM DBA_SEGMENTS S, DBA_INDEXES I WHERE I.INDEX_NAME = S.SEGMENT_NAME AND I.OWNER = S.OWNER AND S.OWNER NOT LIKE '%SYS%' GROUP BY I.OWNER, I.TABLE_OWNER, TABLE_NAME, INDEX_NAME, INDEX_TYPE HAVING SUM(S.BYTES) > 1024 * 1024), TMP2 AS (SELECT INDEX_OWNER, INDEX_NAME, PLAN_OPERATION, (SELECT MIN(TO_CHAR(NB.BEGIN_INTERVAL_TIME, 'YYYY-MM-DD HH24:MI:SS')) FROM DBA_HIST_SNAPSHOT NB WHERE NB.SNAP_ID = V.MIN_SNAP_ID) MIN_DATE, (SELECT MAX(TO_CHAR(NB.END_INTERVAL_TIME, 'YYYY-MM-DD HH24:MI:SS')) FROM DBA_HIST_SNAPSHOT NB WHERE NB.SNAP_ID = V.MAX_SNAP_ID) MAX_DATE, COUNTS FROM (SELECT D.OBJECT_OWNER INDEX_OWNER, D.OBJECT_NAME INDEX_NAME, D.OPERATION || ' ' || D.OPTIONS PLAN_OPERATION, MIN(H.SNAP_ID) MIN_SNAP_ID, MAX(H.SNAP_ID) MAX_SNAP_ID, COUNT(1) COUNTS FROM DBA_HIST_SQL_PLAN D, DBA_HIST_SQLSTAT H WHERE D.OPERATION LIKE '%INDEX%' AND D.SQL_ID = H.SQL_ID GROUP BY D.OBJECT_OWNER, D.OBJECT_NAME, D.OPERATION, D.OPTIONS) V) SELECT A.TABLE_OWNER, A.TABLE_NAME, A.INDEX_OWNER, A.INDEX_NAME, A.CREATED, A.INDEX_TYPE, A.INDEX_MB, A.COUNT_INDEX_COLS, B.PLAN_OPERATION, CASE WHEN MIN_DATE IS NULL THEN (SELECT MIN(TO_CHAR(NB.BEGIN_INTERVAL_TIME, 'YYYY-MM-DD HH24:MI:SS')) FROM DBA_HIST_SNAPSHOT NB) ELSE MIN_DATE END AS MIN_DATE, CASE WHEN MAX_DATE IS NULL THEN (SELECT MAX(TO_CHAR(NB.BEGIN_INTERVAL_TIME, 'YYYY-MM-DD HH24:MI:SS')) FROM DBA_HIST_SNAPSHOT NB) ELSE MAX_DATE END AS MAX_DATE, COUNTS FROM TMP1 A LEFT OUTER JOIN TMP2 B ON (A.INDEX_OWNER = B.INDEX_OWNER AND A.INDEX_NAME = B.INDEX_NAME);

查看某個表索引使用情況
某個用戶的某個表的索引信息
--get the index column information by specified table set linesize 180 col cl_nam format a20 col table_name format a25 col cl_pos format 9 col idx_typ format a15 SELECT b.table_name, a.index_name, a.column_name cl_nam, a.column_position cl_pos, b.status, b.index_type idx_typ, a.descend dscd FROM dba_ind_columns a, dba_indexes b WHERE a.index_name = b.index_name AND owner = upper('&owner') AND a.table_name LIKE upper('%&table_name%') ORDER BY 2, 4;
--查看某個表索引使用情況 SELECT p.object_name, p.operation, p.options, COUNT(1) FROM v$sql_plan p, v$sql s WHERE p.object_owner <> 'SYS' AND p.OBJECT_NAME in (select index_name from dba_indexes where table_name = 'S_SHIP_UNIT_LINE') AND p.sql_id = s.sql_id GROUP BY p.object_name, p.operation, p.options ORDER BY 1, 2, 3; --查看歷史索引使用情況 SELECT p.object_name, p.operation, p.options, COUNT(1) FROM dba_hist_sql_plan p, dba_hist_sqlstat s WHERE p.object_owner <> 'SYS' AND p.object_name in (select index_name from dba_indexes where table_name = 'S_SHIP_UNIT_LINE') AND p.sql_id = s.sql_id GROUP BY p.object_name, p.operation, p.options ORDER BY 1, 2, 3;
附錄:
1、獲得索引使用頻率腳本(idx_usage_detail.sql)
set linesize 140 set pagesize 160 clear breaks clear computes break on TABLE_NAME skip 2 ON INDEX_NAME ON INDEX_TYPE ON MB compute sum of NR_EXEC on TABLE_NAME SKIP 2 compute sum of MB on TABLE_NAME SKIP 2 SET TIMI OFF set linesize 140 set pagesize 10000 set verify off col OWNER noprint col TABLE_NAME for a30 heading 'Table name' col INDEX_NAME for a30 heading 'Index name' col INDEX_TYPE for a15 heading 'Index type' col INDEX_OPERATION for a21 Heading 'Index operation' col NR_EXEC for 9G999G990 heading 'Executions' col MB for 999G990D90 Heading 'Index|Size MB' justify right WITH Q AS ( SELECT S.OWNER A_OWNER, TABLE_NAME A_TABLE_NAME, INDEX_NAME A_INDEX_NAME, INDEX_TYPE A_INDEX_TYPE, SUM(S.bytes) / 1048576 A_MB FROM DBA_SEGMENTS S, DBA_INDEXES I WHERE S.OWNER = '&&1' AND I.OWNER = '&&1' AND INDEX_NAME = SEGMENT_NAME GROUP BY S.OWNER, TABLE_NAME, INDEX_NAME, INDEX_TYPE HAVING SUM(S.BYTES) > 1048576 * &&2 ) SELECT /*+ NO_QUERY_TRANSFORMATION(S) */ A_OWNER OWNER, A_TABLE_NAME TABLE_NAME, A_INDEX_NAME INDEX_NAME, A_INDEX_TYPE INDEX_TYPE, A_MB MB, DECODE (OPTIONS, null, ' -',OPTIONS) INDEX_OPERATION, COUNT(OPERATION) NR_EXEC FROM Q, DBA_HIST_SQL_PLAN d WHERE D.OBJECT_OWNER(+)= q.A_OWNER AND D.OBJECT_NAME(+) = q.A_INDEX_NAME GROUP BY A_OWNER, A_TABLE_NAME, A_INDEX_NAME, A_INDEX_TYPE, A_MB, DECODE (OPTIONS, null, ' -',OPTIONS) ORDER BY A_OWNER, A_TABLE_NAME, A_INDEX_NAME, A_INDEX_TYPE, A_MB DESC, NR_EXEC DESC ; PROMPT "Showed only indexes in &&1 schema whose size > &&2 MB in period:" SET HEAD OFF; select to_char (min(BEGIN_INTERVAL_TIME), 'DD.MM.YYYY') || '-' || to_char (max(END_INTERVAL_TIME), 'DD.MM.YYYY') from dba_hist_snapshot; SET HEAD ON SET TIMI ON
2、索引質量分析腳本
--1、script name: idx_quality.sql --Author : Leshami --index quality retrieval SET LINESIZE 145 SET PAGESIZE 1000 SET VERIFY OFF CLEAR COMPUTES CLEAR BREAKS BREAK ON table_name ON num_rows ON blocks COLUMN owner FORMAT a14 HEADING 'Index owner' COLUMN table_name FORMAT a25 HEADING 'Table' COLUMN index_name FORMAT a25 HEADING 'Index' COLUMN num_rows FORMAT 999G999G990 HEADING 'Table|Rows' COLUMN MB FORMAT 9G990 HEADING 'Index|Size MB' COLUMN blocks HEADING 'Table|Blocks' COLUMN num_blocks FORMAT 9G990 HEADING 'Data|Blocks' COLUMN avg_data_blocks_per_key FORMAT 999G990 HEADING 'Data Blks|per Key' COLUMN avg_leaf_blocks_per_key FORMAT 999G990 HEADING 'Leaf Blks|per Key' COLUMN clustering_factor FORMAT 999G999G990 HEADING 'Clust|Factor' COLUMN Index_Quality FORMAT A13 HEADING 'Index|Quality' --SPOOL index_quality SELECT i.table_name, t.num_rows, t.blocks, i.index_name, o.bytes / 1048576 mb, i.avg_data_blocks_per_key, i.avg_leaf_blocks_per_key, i.clustering_factor, CASE WHEN NVL (i.clustering_factor, 0) = 0 THEN '0-No Stats' WHEN NVL (t.num_rows, 0) = 0 THEN '0-No Stats' WHEN (ROUND (i.clustering_factor / t.num_rows * 100)) < 6 THEN '5-Excellent' WHEN (ROUND (i.clustering_factor / t.num_rows * 100)) BETWEEN 7 AND 11 THEN '4-Very Good' WHEN (ROUND (i.clustering_factor / t.num_rows * 100)) BETWEEN 12 AND 15 THEN '2-Good' WHEN (ROUND (i.clustering_factor / t.num_rows * 100)) BETWEEN 16 AND 25 THEN '2-Fair' ELSE '1-Poor' END index_quality FROM dba_indexes i, dba_segments o, dba_tables t WHERE -- i.index_name LIKE UPPER ('%&&1%') AND i.owner = t.owner AND i.table_name = t.table_name AND i.owner = o.owner AND i.index_name = o.segment_name AND t.owner = UPPER('&input_owner') AND t.table_name LIKE UPPER('%&input_tbname%') ORDER BY table_name, num_rows, blocks, index_quality DESC; --SPOOL OFF; ============================================================== --2、獲取指定schema或表上的索引質量信息報告 SQL> @idx_quality.sql Enter value for input_owner: RFUSER Enter value for input_tbname: TAB_GOODSLABEL --省略具體的表名則會輸出整個schema的索引質量報告