1. 程式人生 > 實用技巧 >Oracle刪除索引規範

Oracle刪除索引規範

1.背景概述

近期應用升級上線過程中,存在刪除業務表索引的變更操作,且因刪除索引導致次日業務高峰時期,資料庫響應緩慢的情況,經定位是缺失索引導致。與使用者溝通,雖然變更中刪除索引的需求很少,但也存在此類需求。
本文從資料庫層面,旨在儘可能避免類似問題發生,制定刪除索引的變更規範。

2.索引刪除規範

若確認需要做索引刪除,可以使用Oracle提供的兩個功能特性協助判斷刪除索引是否會有隱患。

2.1 增加索引監控

將計劃要刪除的索引經過至少一個業務週期(具體業務確認業務週期為多久,注意要考慮到跑批場景)的監控,如果整個業務週期,該索引一直沒有被使用過則可以考慮刪除。
演示案例:

create table T as select * from dba_objects;
create index IDX_T_01 on T(object_id);

假設要刪除的索引名稱是IDX_T_01,使用下面語句開啟該索引的監控。

alter index jingyu.IDX_T_01 monitoring usage;

索引是否使用到,會在具體業務schema下的v$object_usage檢視中體現(具體觀察USED這一列的值,如果是NO,說明自監控以來該索引從未使用過)

conn jingyu/jingyu
col index_name for a30
col table_name for a30
col START_MONITORING for a30
col END_MONITORING for a30
set lines 180
select * from v$object_usage;

INDEX_NAME TABLE_NAME MONITO USED   START_MONITORING               END_MONITORING
---------- ---------- ------ ------ ------------------------------ ------------------------------
IDX_T_01   T          YES    NO     07/22/2020 14:15:18

如果有人/應用執行過用到該索引的語句,比如:

select object_id from t where object_id = 3;

此時再觀察USED這一列的值,已經變為yes,說明自監控以來該索引有被使用過,就不能被輕易刪除:

INDEX_NAME TABLE_NAME MONITO USED   START_MONITORING               END_MONITORING
---------- ---------- ------ ------ ------------------------------ ------------------------------
IDX_T_01   T          YES    YES    07/22/2020 14:15:18

如果不再需要監控該索引,可以這樣取消該索引的監控:

alter index jingyu.IDX_T_01 nomonitoring usage;


INDEX_NAME TABLE_NAME MONITO USED   START_MONITORING               END_MONITORING
---------- ---------- ------ ------ ------------------------------ ------------------------------
IDX_T_01   T          NO     NO     07/22/2020 14:30:30            07/22/2020 14:30:58

優點:簡單,能有效監控整個業務週期內索引是否被使用到,如果沒有被使用則可以放心刪除。
缺點:只能判斷是否被使用到,不能判斷索引使用頻率。

2.2 將刪除索引先修改為不可見

將計劃要刪除的索引設定為不可見(invisible),然後經歷至少一個業務週期(具體業務確認業務週期為多久,注意要考慮到跑批場景)的觀察,確認沒有影響,則可以考慮徹底刪除。

設定索引IDX_T_01不可見:

alter index jingyu.IDX_T_01 invisible;

執行演示SQL發現已經是全表掃:

explain plan for select object_id from t where object_id = 3;
select * from table(dbms_xplan.display());
PLAN_TABLE_OUTPUT
----------------------------------------------------------------------------------------------------
Plan hash value: 1601196873

--------------------------------------------------------------------------
| Id  | Operation         | Name | Rows  | Bytes | Cost (%CPU)| Time     |
--------------------------------------------------------------------------
|   0 | SELECT STATEMENT  |      |    11 |   143 |   283   (2)| 00:00:04 |
|*  1 |  TABLE ACCESS FULL| T    |    11 |   143 |   283   (2)| 00:00:04 |
--------------------------------------------------------------------------

恢復索引IDX_T_01可見:

alter index jingyu.IDX_T_01 visible;

執行演示SQL發現又恢復了索引訪問,無需重建:

explain plan for select object_id from t where object_id = 3;
select * from table(dbms_xplan.display());
PLAN_TABLE_OUTPUT
----------------------------------------------------------------------------------------------------
Plan hash value: 2968633466

-----------------------------------------------------------------------------
| Id  | Operation        | Name     | Rows  | Bytes | Cost (%CPU)| Time     |
-----------------------------------------------------------------------------
|   0 | SELECT STATEMENT |          |     1 |    13 |     1   (0)| 00:00:01 |
|*  1 |  INDEX RANGE SCAN| IDX_T_01 |     1 |    13 |     1   (0)| 00:00:01 |
-----------------------------------------------------------------------------

優點:因為invisible索引只是讓優化器不可見,索引段中的資料依然存在且DML操作也會維護這些invisible的索引,所以回退(直接修改該索引為可見)非常方便。
缺點:如果刪除索引是為了更快載入資料,那麼設定索引invisible期間,並不會提升效率。另外應用會話如果有設定OPTIMIZER_USE_INVISIBLE_INDEXES=TRUE的引數,也會用到invisible索引,而這可能會造成誤判,需要特別注意。

3.根本解決方案及建議

刪除索引的情景一般是考慮到索引數量過多,從而導致索引維護成本和空間使用成本增加。一般原則是首先評估刪除冗餘索引,比如某張表同時有兩個索引,索引A是c1列,索引B是c1,c2兩列的複合索引,則一般可以選擇刪除索引A;但需要注意,如果索引B是c2和c1列的複合索引,就通常不可以刪除索引A。其次,對其他計劃刪除的索引可以按照上文的規範來評估和操作。