索引表空間不足的幾個處理思路
白天一個朋友來電,諮詢這樣一個場景:生產環境上一個索引表空間,由於事先規劃有問題,出現空間不足。申請額外空間需要走正式流程需要時間,問臨時有沒有什麼好方法?
表空間對應的索引實際上是一張核心資料表的索引所在空間。由於經常性的進行資料匯入操作,引起索引空間的不足。經過思考,在短時間內申請不到額外資源的情況下,可以從幾個方面去進行嘗試。
1、實驗環境準備
朋友的環境是Oracle 10g,所以對應使用相似的實驗環境。
SQL> select * from v$version;
BANNER
----------------------------------------------------------------
Oracle Database 10g Enterprise Edition Release 10.2.0.1.0 - Prod
PL/SQL Release 10.2.0.1.0 - Production
CORE 10.2.0.1.0 Production
TNS for 32-bit Windows: Version 10.2.0.1.0 - Production
NLSRTL Version 10.2.0.1.0 – Production
2、嘗試索引rebuild
對很多DBA而言,索引定期rebuild是維護相關查詢效率的重要日常工作。很多時候,經常性的對一些索引進行rebuild重構操作,的確可以最佳化索引結構,提高執行作業效率。
在以前的Blog中,筆者討論過對於定期rebuild索引的見解,此處不重複累述(http://space.itpub.net/17203031/spacelist-blog-itemtypeid-84194)。這裡要強調的是,相對於堆表(Heap Table)結構,普通索引的空間使用上,是有不同的。
下面構建實驗環境資料表T:
SQL> select count(*) from t;
COUNT(*)
----------
202872
SQL> create index idx_t_name on t(object_name);
Index created
SQL> exec dbms_stats.gather_table_stats(user,'T',cascade => true);
PL/SQL procedure successfully completed
SQL> select segment_name, bytes from dba_segments where segment_name in ('T','IDX_T_NAME') and wner='SCOTT';
SEGMENT_NAME BYTES
-------------------- ----------
T 24117248
IDX_T_NAME 9437184
此時,我們刪除資料表中資料,重新收集統計量。
SQL> delete t;
202872 rows deleted
SQL> commit;
Commit complete
SQL> exec dbms_stats.gather_table_stats(user,'T',cascade => true);
PL/SQL procedure successfully completed
SQL> select segment_name, bytes from dba_segments where segment_name in ('T','IDX_T_NAME') and wner='SCOTT';
SEGMENT_NAME BYTES
-------------------- ----------
T 24117248
IDX_T_NAME 9437184
注意:我們將資料刪除掉之後,資料表和索引的分配空間是不會回收的。堆表(Heap Table)的空閒結構,會在日後資料插入(非direct load)方式時被利用起來。但是,索引標註為刪除的葉子節點,卻可能不會被重用!
如果索引列是那種單向遞增的取值方式,如使用sequence生成的資料值,所新插入的數值都是在葉子節點的右側高位上。這樣的話,過去被刪除的葉子節點是不會別利用上的。從而,索引的體積就只能單向的不斷膨脹。
解決的方法,就是進行週期性的rebuild操作。
SQL> alter index idx_t_name rebuild;
Index altered
SQL> select segment_name, bytes from dba_segments where segment_name in ('T','IDX_T_NAME') and wner='SCOTT';
SEGMENT_NAME BYTES
-------------------- ----------
T 24117248
IDX_T_NAME 65536
注意:有的時候,rebuild也是需要額外的一些空間使用的,所以在資源特別緊張的時候,可以先unuable掉索引,再進行rebuild操作。
3、索引物件壓縮
壓縮索引段物件,是另一種解決問題的方法。在Oracle的各個版本中,一直在不斷完善壓縮技術。希望實現一種對DML操作效能影響最小的壓縮技術。
SQL> create table t as select owner a, owner b from dba_objects;
Table created
SQL> select count(*) from t;
COUNT(*)
----------
53301
SQL> create index idx_t_ownernocompr on t(a);
Index created
SQL> create index idx_t_ownercompr on t(b) compress;
Index created
SQL> exec dbms_stats.gather_table_stats(user,'T',cascade => true);
PL/SQL procedure successfully completed
在構建索引時,使用compress關鍵字,可以定義壓縮索引段結構。空間使用情況如下:
SQL> select index_name, compression from dba_indexes where wner='SCOTT' and table_name='T';
INDEX_NAME COMPRESSION
------------------------------ -----------
IDX_T_OWNERNOCOMPR DISABLED
IDX_T_OWNERCOMPR ENABLED
SQL> select segment_name, bytes, blocks from dba_segments where segment_name in ('IDX_T_OWNERNOCOMPR','IDX_T_OWNERCOMPR');
SEGMENT_NAME BYTES BLOCKS
-------------------- ---------- ----------
IDX_T_OWNERNOCOMPR 2097152 256
IDX_T_OWNERCOMPR 786432 96
可以看出,壓縮的索引物件可以節省空間使用。同時,對執行計劃來說,壓縮索引也是可以出現在執行計劃中的。
SQL> create table t_back as select * from t;
Table created
SQL> select * from table(dbms_xplan.display);
PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------
Plan hash value: 441125606
--------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost
--------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 2235 | 26820 | 20
| 1 | TABLE ACCESS BY INDEX ROWID| T | 2235 | 26820 | 20
|* 2 | INDEX RANGE SCAN | IDX_T_OWNERNOCOMPR | 2235 | | 6
--------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - access("A"='SCOTT')
14 rows selected
SQL> explain plan for select * from t where b='SCOTT';
Explained
SQL> select * from table(dbms_xplan.display);
PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------
Plan hash value: 2961582115
--------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%
--------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 2235 | 26820 | 18
| 1 | TABLE ACCESS BY INDEX ROWID| T | 2235 | 26820 | 18
|* 2 | INDEX RANGE SCAN | IDX_T_OWNERCOMPR | 2235 | | 4
--------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - access("B"='SCOTT')
14 rows selected
注意:壓縮索引,特別是11g之前的壓縮索引雖然壓縮比例尚可,但是對DML操作來說,必然存在一定的效能影響。這個方面到了11g有了根本性的改善,11g中推出的Advanced Compression元件,針對各種型別資料提供了全新的壓縮解決方案,同時其中的OLTP屬性,將壓縮對DML操作的影響降到最小。
4、分割槽索引使用
另外還有一種思路,就是建立在分割槽表基礎上。朋友的資料表是一張分割槽表,而且每次主要使用的就是一個分割槽的資料。那麼,可否只是啟用這個分割槽的索引,其他分割槽的索引不生成或者失效呢?
注意:分割槽表的索引分為全域性索引Global Index和本地索引Local Index兩個型別。如果是全域性索引,這種思路就不成立,因為索引段對應是一個。如果是Local Index,這種可能性是存在的。
SQL> create table t
2 partition by list(owner)
3 (
4 partition t_list_sys values ('SYS'),
5 partition t_list_scott values ('SCOTT'),
6 partition t_list_hr values ('HR'),
7 partition t_list_others values (default)
8 )
9 as select * from dba_objects where 1=0;
Table created
SQL> insert into t select * from dba_objects;
50727 rows inserted
SQL> commit;
Commit complete
建立本地索引。
SQL> create index idx_t_idlocal on t(object_id);
Index created
SQL> select segment_name, partition_name, bytes from user_segments where segment_name='T';
SEGMENT_NAME PARTITION_NAME BYTES
-------------------- ------------------------------ ----------
T T_LIST_SYS 3145728
T T_LIST_SCOTT 65536
T T_LIST_HR 65536
T T_LIST_OTHERS 4194304
SQL> create index idx_t_idlocal on t(object_id) local;
Index created
SQL> exec dbms_stats.gather_table_stats(user,'T',cascade => true);
PL/SQL procedure successfully completed
SQL> select index_name, index_type, status from user_indexes where index_name='IDX_T_IDLOCAL';
INDEX_NAME INDEX_TYPE STATUS
------------------------------ --------------------------- --------
IDX_T_IDLOCAL NORMAL N/A
SQL> select index_name, partition_name, status from user_ind_partitions;
INDEX_NAME PARTITION_NAME STATUS
------------------------------ ------------------------------ --------
IDX_T_IDLOCAL T_LIST_SCOTT USABLE
IDX_T_IDLOCAL T_LIST_SYS USABLE
IDX_T_IDLOCAL T_LIST_HR USABLE
IDX_T_IDLOCAL T_LIST_OTHERS USABLE
可以透過部分unusable的方法,只啟用一部分的索引段物件。
SQL> alter index idx_t_idlocal unusable;
Index altered
SQL> select index_name, partition_name, status from user_ind_partitions;
INDEX_NAME PARTITION_NAME STATUS
------------------------------ ------------------------------ --------
IDX_T_IDLOCAL T_LIST_SCOTT UNUSABLE
IDX_T_IDLOCAL T_LIST_HR UNUSABLE
IDX_T_IDLOCAL T_LIST_OTHERS UNUSABLE
IDX_T_IDLOCAL T_LIST_SYS UNUSABLE
SQL> alter index idx_t_idlocal rebuild;
alter index idx_t_idlocal rebuild
ORA-14086: 不能將分割槽索引作為整體重建
SQL> alter index idx_t_idlocal rebuild partition T_LIST_SYS;
Index altered
SQL> select index_name, partition_name, status from user_ind_partitions;
INDEX_NAME PARTITION_NAME STATUS
------------------------------ ------------------------------ --------
IDX_T_IDLOCAL T_LIST_SCOTT UNUSABLE
IDX_T_IDLOCAL T_LIST_HR UNUSABLE
IDX_T_IDLOCAL T_LIST_OTHERS UNUSABLE
IDX_T_IDLOCAL T_LIST_SYS USABLE
本地索引的rebuild,是透過每個部分分割槽分別進行rebuild。當一部分分割槽usable,另一部分unusable的時候,處在usable狀態的索引是可以生效使用的。
SQL> explain plan for select * from t where wner='SYS' and object_id=1000;
Explained
SQL> select * from table(dbms_xplan.display);
PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------
Plan hash value: 2092295073
--------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cos
--------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 92 |
| 1 | PARTITION LIST SINGLE | | 1 | 92 |
|* 2 | TABLE ACCESS BY LOCAL INDEX ROWID| T | 1 | 92 |
|* 3 | INDEX RANGE SCAN | IDX_T_IDLOCAL | 1 | |
--------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - filter("OWNER"='SYS')
3 - access("OBJECT_ID"=1000)
16 rows selected
SQL> explain plan for select * from t where wner='SCOTT' and object_id=1000;
Explained
SQL> select * from table(dbms_xplan.display);
PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------
Plan hash value: 882533222
--------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | P
--------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 85 | 3 (0)| 00:00:01 |
| 1 | PARTITION LIST SINGLE| | 1 | 85 | 3 (0)| 00:00:01 |
|* 2 | TABLE ACCESS FULL | T | 1 | 85 | 3 (0)| 00:00:01 |
--------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - filter("OBJECT_ID"=1000)
14 rows selected
同時,並不影響insert等操作。
SQL> insert into t select * from dba_objects;
50726 rows inserted
SQL> commit;
Commit complete
但是,一部分索引處在unusable狀態,並不是沒有問題。在重新收集統計量的時候,Oracle會報錯。
SQL> exec dbms_stats.gather_table_stats(user,'T',cascade => true);
begin dbms_stats.gather_table_stats(user,'T',cascade => true); end;
ORA-20000: index "SCOTT"."IDX_T_IDLOCAL" or partition of such index is in unusable state
ORA-06512: 在 "SYS.DBMS_STATS", line 13056
ORA-06512: 在 "SYS.DBMS_STATS", line 13076
ORA-06512: 在 line 1
所以,這種方法也只是權宜之計。
5、暫時rebuild到另一表空間
一個表空間空間缺少,可以暫時性的將索引rebuild到其他稍微空閒的表空間中,作為臨時的替代。
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/17203031/viewspace-712765/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- sysaux 表空間不足問題處理UX
- oracle 表空間 不足時如何處理Oracle
- 如何處理表空間級別,表級別,索引級別的碎片索引
- Jenkins臨時空間不足處理辦法Jenkins
- undo表空間故障處理
- UNDO表空間損壞的處理
- 伺服器儲存空間不足怎麼處理?伺服器
- win10備份空間不足怎麼辦_win10備份空間不足如何處理Win10
- [20170203]dg磁碟空間不足的處理.txt
- 關於索引空間的重用的幾個場景索引
- undo表空間出現問題的幾種情況與處理
- 一次HASH JOIN 臨時表空間不足的分析和優化思路優化
- system表空間不足的問題分析
- undo 表空間滿了的處理方法
- 處理TEMP表空間滿的問題
- undo表空間佔用磁碟空間滿案例處理
- UNDO表空間不足解決方法
- sysaux 表空間爆滿處理方法UX
- Oracle Temp臨時表空間處理Oracle
- system表空間不足的問題分析(二)
- Oracle undo表空間爆滿的處理方法Oracle
- undo表空間損壞的處理過程
- TEMP表空間不足解決 - temp group
- 表空間資料檔案故障處理
- 刪除臨時表空間hang處理
- 傳輸表空間及問題處理
- oracle臨時表空間過大的原因&&處理Oracle
- sysaux表空間檔案損壞的處理(zt)UX
- 表空間使用情況查詢慢的處理
- TEMP表空間報ORA-1652的處理
- 批量處理時臨時增加回滾表空間臨時表空間檔案
- Oracle表、索引修改表空間語句Oracle索引
- Oracle中表空間、表、索引的遷移Oracle索引
- 系統臨時表空間不足問題
- dataguard之邏輯備庫表空間不足
- oracle中undo表空間丟失處理方法Oracle
- oracle sysaux表空間滿了處理辦法OracleUX
- 週末又一次歸檔空間不足問題處理