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。其次,對其他計划刪除的索引可以按照上文的規范來評估和操作。