Oracle分區表刪除分區引發錯誤ORA-01502: 索引或這類索引的分區處於不可用狀態

来源:https://www.cnblogs.com/lijiaman/archive/2018/07/07/9277149.html
-Advertisement-
Play Games

(一)問題: 最近在做Oracle數據清理,在對分區表進行數據清理時,採用的方法是drop partition,刪除的過程中,沒有遇到任何問題,大概過了10分鐘,開發人員反饋部分分區表上的業務失敗。具體錯誤為: ORA-01502錯誤:索引或這類索引的分區處於不可用狀態(英文:ora-01502:i... ...


(一)問題:

最近在做Oracle數據清理,在對分區表進行數據清理時,採用的方法是drop partition,刪除的過程中,沒有遇到任何問題,大概過了10分鐘,開發人員反饋部分分區表上的業務失敗。具體錯誤為:

ORA-01502錯誤:索引或這類索引的分區處於不可用狀態(英文:ora-01502:index 'schema.index_name' or partition of such index is in unusable state)。

(二)原因分析

查看出現問題的分區表,均有一個共同點:表上以“pk_”開頭的索引為unusable狀態,以“pk_”開頭的索引是隨創建主鍵約束而創建的。當用戶在創建主鍵約束或唯一性約束的時候,會在相應的列上創建唯一性索引

經過查證,發現是在刪除分區的時候,導致分區表上的唯一性全局索引為不可用狀態,導致新的數據無法正常插入,從而引發了該錯誤。

是不是索引不可用會導致DML操作失敗呢?經過驗證,發現以下特點:

1.對於非唯一性索引,如果索引不可用,是不會影響到到DML操作的;

2.對於唯一性索引,如果索引不可用,在進行DML操作時,會觸發ORA-01502錯誤;

 

這裡記錄一下哪些操作會導致索引失效:

image

                                                              圖1.索引失效原因總結

(三)解決方案

(3.1)瞭解唯一性索引

在解決問題之前,我們來分析一下,哪些行為會創建唯一性索引(3種):

--直接創建唯一性索引。

     語法為:CREATE UNIQUE INDEX index_name on table_name(col1,col2,…);

--創建主鍵約束時自動創建唯一性索引。

     語法為:ALTER TABLE table_name ADD CONSTRAINT constraint_name PRIMARY KEY(col1,col2,..);

--創建唯一性約束時自動創建唯一性索引。

     語法為:ALTER TABLE table_name ADD CONSTRAINT constraint_name UNIQUE(col1,col2,…);

 

這裡,我總結了3套方案來對應ORA-01502問題。

(3.2)方案一:刪除唯一性索引

與業務方面溝通,確認唯一性索引是否可以刪除,如果可以,直接刪除索引,刪除語法為:

SQL> DROP INDEX schema.index_name;

對於由主鍵約束或唯一性約束創建的唯一性索引,不能直接刪除

SQL> drop index lijiaman.sale_pk;
drop index lijiaman.sale_pk

ORA-02429: cannot drop index used for enforcement of unique/primary key

正確的方法是刪除相應的約束。

SQL> alter table sales drop constraint sale_pk;

Table altered

小結:該方法簡單粗暴,前提是在約束或索引在業務方面可以刪除的情況下才能使用。

(3.3)方案二:重建唯一性索引(針對非分區表)

語法為:

SQL> ALTER INDEX [schema.]index_name REBUILD [ONLINE] [TABLESPACE tablespace name]

小結:該方法可以使索引可用。但對於分區表而言,依然存在問題:在下一次刪除分區後,索引狀態又會變為不可用。

(3.4)方案三:刪除不可用的索引,創建唯一性分區索引(針對分區表)

創建唯一性分區索引:

SQL> CREATE UNIQUE INDEX index_name on [schema.]table(col1,col2,...);

對於主鍵約束、唯一性約束,可以使用以下語法添加唯一性局部分區索引:

SQL> ALTER TABLE [schema.]table_name ADD CONSTRAINT constarint [PRIMARY KEY | UNIQUE](col1,col2)
     USING INDEX LOCAL TABLESPACE tablespace_name;

小結:該方法可以有效解決分區表因刪除分區導致的索引不可用問題。

 

 

附錄:模擬實驗

(1)首先模擬生產情況,創建一張表:

create table sales
(
  prod_id number,
  cust_id number,
  time_id date,
  quantity_sold number(3)
)
partition by range(time_id)
(
  partition sales_q1_2017 values less than(to_date('1-4-2017','dd-mm-yyyy')) ,
  partition sales_q2_2017 values less than(to_date('1-7-2017','dd-mm-yyyy')) ,
  partition sales_q3_2017 values less than(to_date('1-10-2017','dd-mm-yyyy')) ,
  partition sales_q4_2017 values less than(to_date('1-1-2018','dd-mm-yyyy'))
);

插入數據,確保每個分區都有數據

insert into sales(prod_id,cust_id,time_id,quantity_sold)values(1,11,to_date('2017-02-01','yyyy-mm-dd'),103);
insert into sales(prod_id,cust_id,time_id,quantity_sold)values(2,12,to_date('2017-06-01','yyyy-mm-dd'),103);
insert into sales(prod_id,cust_id,time_id,quantity_sold)values(3,14,to_date('2017-08-01','yyyy-mm-dd'),103);
insert into sales(prod_id,cust_id,time_id,quantity_sold)values(4,14,to_date('2017-12-01','yyyy-mm-dd'),103);

檢查一下資料庫的數據信息

SQL> select * from sales;        --查看整個分區表的數據

   PROD_ID    CUST_ID TIME_ID     QUANTITY_SOLD
---------- ---------- ----------- -------------
         1         11 2017/2/1              103
         2         12 2017/6/1              103
         3         14 2017/8/1              103
         4         14 2017/12/1             103

SQL> select * from sales partition(sales_q1_2017);      --查看分區“sales_q1_2017”的數據

   PROD_ID    CUST_ID TIME_ID     QUANTITY_SOLD
---------- ---------- ----------- -------------
         1         11 2017/2/1              103

(2)由於出現ORA-01502問題時,與表相關的對象只有主鍵約束和索引。所以,我在表上創建了索引和約束,並確認了所有索引可用

alter table sales add constraint sale_pk primary key(time_id,cust_id);  --創建主鍵約束
create index inx_sales_1 on sales(cust_id);  --創建普通(全局)索引
create index inx_sales_2 on sales(time_id) local;  --創建局部分區索引

確認索引狀態:

SQL> select   owner,table_name,index_name,status
  2  from     dba_indexes
  3  where    owner = 'LIJIAMAN'
  4  and      table_name = 'SALES';

OWNER                          TABLE_NAME                     INDEX_NAME                     STATUS
------------------------------ ------------------------------ ------------------------------ --------
LIJIAMAN                       SALES                          INX_SALES_2                    N/A
LIJIAMAN                       SALES                          SALE_PK                        VALID
LIJIAMAN                       SALES                          INX_SALES_1                    VALID

對於索引“SALES_PK”和“INX_SALES_1”,索引狀態為可用,那”INX_SALES_2“這個索引狀態為”N/A“,這又是怎麼回事麽?經過查找資料,確認索引共有四種狀態:

  • N/A         :說明這個是分區索引需要查user_ind_partitions或者user_ind_subpartitions來確定每個分區是否可用;
  • VAILD      :說明這個索引可用;
  • UNUSABLE:說明這個索引不可用;
  • USABLE    :說明這個索引的分區是可用的。

我們再去查看數據字典DBA_IND_PARTITIONS,確認”INX_SALES_2”的狀態,索引可用。

SQL> SELECT INDEX_OWNER,INDEX_NAME,PARTITION_NAME,STATUS FROM DBA_IND_PARTITIONS I WHERE I.INDEX_OWNER = 'LIJIAMAN' AND I.INDEX_NAME = 'INX_SALES_2';

INDEX_OWNER                    INDEX_NAME                     PARTITION_NAME                 STATUS
------------------------------ ------------------------------ ------------------------------ --------
LIJIAMAN                       INX_SALES_2                    SALES_Q1_2017                  USABLE
LIJIAMAN                       INX_SALES_2                    SALES_Q2_2017                  USABLE
LIJIAMAN                       INX_SALES_2                    SALES_Q3_2017                  USABLE
LIJIAMAN                       INX_SALES_2                    SALES_Q4_2017                  USABLE

確認主鍵約束的狀態,確認可用

SQL> select   owner,table_name,constraint_name,constraint_type,status,deferrable,deferred,validated
  2  from     dba_constraints
  3  where    owner = 'LIJIAMAN'
  4  and      table_name = 'SALES';

OWNER     TABLE_NAME   CONSTRAINT_NAME   CONSTRAINT_TYPE STATUS   DEFERRABLE     DEFERRED  VALIDATED
--------- ------------ ----------------- --------------- -------- -------------- --------- -------------
LIJIAMAN  SALES        SALE_PK           P               ENABLED  NOT DEFERRABLE IMMEDIATE VALIDATED

(3)接下來,我們模擬數據清理,刪除分區”sales_q1_2017“

SQL> alter table sales drop partition sales_q1_2017 ;

Table altered

查看分區表的數據,可以看到,分區”sales_q1_2017“的數據已經隨著分區被刪除

SQL> select * from sales;

   PROD_ID    CUST_ID TIME_ID     QUANTITY_SOLD
---------- ---------- ----------- -------------
         2         12 2017/6/1              103
         3         14 2017/8/1              103
         4         14 2017/12/1             103

 

==================轉折點==========================

 

(4)此時,我們模擬正常的業務交易,發現如下情況

    --對於insert操作,無法完成,報ORA-01502錯誤;

    --對於delete操作,無法完成,報ORA-01502錯誤;

    --對於update操作,如果不涉及到主鍵相關的列,則可以執行成功,如果涉及到主鍵列,報ORA-01502錯誤;

--數據插入測試,發現無法插入數據
SQL> insert into sales(prod_id,cust_id,time_id,quantity_sold)values(5,15,to_date('2017-8-01','yyyy-mm-dd'),103);
insert into sales(prod_id,cust_id,time_id,quantity_sold)values(5,15,to_date('2017-8-01','yyyy-mm-dd'),103)
ORA-01502: index 'LIJIAMAN.SALE_PK' or partition of such index is in unusable state

--數據刪除測試,發現無法刪除數據
SQL> delete from sales where prod_id = 3 ;
delete from sales where prod_id = 3
ORA-01502: index 'LIJIAMAN.SALE_PK' or partition of such index is in unusable state

--數據跟新測試,測試3次,發現涉及到與主鍵相關的列,就會更新失敗,其他情況更新成功
SQL> update sales set QUANTITY_SOLD = 105 where PROD_ID = 2;
1 row updated
SQL> commit;
Commit complete

SQL> update sales set QUANTITY_SOLD = 105 where cust_id = 12;
1 row updated
SQL> commit;
Commit complete

SQL> update sales set cust_id = 15 where PROD_ID = 2;
update sales set cust_id = 15 where PROD_ID = 2
ORA-01502: index 'LIJIAMAN.SALE_PK' or partition of such index is in unusable state

再次確認,索引的狀態,可以看到,普通索引狀態已經轉變為不可用,而局部分區索引狀態未發生改變。

SQL> select   owner,table_name,index_name,status
  2  from     dba_indexes
  3  where    owner = 'LIJIAMAN'
  4  and      table_name = 'SALES';

OWNER                          TABLE_NAME                     INDEX_NAME                     STATUS
------------------------------ ------------------------------ ------------------------------ --------
LIJIAMAN                       SALES                          INX_SALES_2                    N/A
LIJIAMAN                       SALES                          SALE_PK                        UNUSABLE
LIJIAMAN                       SALES                          INX_SALES_1                    UNUSABLE


SQL> SELECT INDEX_OWNER,INDEX_NAME,PARTITION_NAME,STATUS FROM DBA_IND_PARTITIONS I WHERE I.INDEX_OWNER = 'LIJIAMAN' AND I.INDEX_NAME = 'INX_SALES_2';

INDEX_OWNER                    INDEX_NAME                     PARTITION_NAME                 STATUS
------------------------------ ------------------------------ ------------------------------ --------
LIJIAMAN                       INX_SALES_2                    SALES_Q2_2017                  USABLE
LIJIAMAN                       INX_SALES_2                    SALES_Q3_2017                  USABLE
LIJIAMAN                       INX_SALES_2                    SALES_Q4_2017                  USABLE

主鍵約束狀態也為發生改變

OWNER      TABLE_NAME   CONSTRAINT_NAME  CONSTRAINT_TYPE STATUS   DEFERRABLE     DEFERRED  VALIDATED
---------- ------------ ---------------- --------------- -------- -------------- --------- -------------
LIJIAMAN   SALES        SALE_PK          P               ENABLED  NOT DEFERRABLE IMMEDIATE VALIDATED

這裡,我們對deop分區前後表的信息對比做一個小結

  刪除分區前 刪除分區後
查詢(select) 正常 正常
插入(insert) 正常 無法插入
刪除(delete) 正常 無法刪除
更新(update) 正常 設計到主鍵相關的列,更新失敗,其他情況更新成功
約束狀態(constraint) 可用 可用
索引狀態(index) 全部可用 1.分區索引可用
2.主鍵約束上的唯一性索引不可用
3.普通索引不可用

通過對比,我們可以推測,索引不可用導致了無法正常DML操作。那麼到底是哪個索引導致的問題呢?

(5)首先測試普通索引,先重建索引INX_SALES_1

SQL> alter index lijiaman.inx_sales_1 rebuild;

Index altered

SQL> select   owner,table_name,index_name,status
  2  from     dba_indexes
  3  where    owner = 'LIJIAMAN'
  4  and      table_name = 'SALES';

OWNER                          TABLE_NAME                     INDEX_NAME                     STATUS
------------------------------ ------------------------------ ------------------------------ --------
LIJIAMAN                       SALES                          INX_SALES_2                    N/A
LIJIAMAN                       SALES                          SALE_PK                        UNUSABLE
LIJIAMAN                       SALES                          INX_SALES_1                    VALID

繼續模擬DML交易,情況與刪除分區後的DML結果相同,可以確認,普通索引不可用並不會引起DML操作失敗

--數據依然無法插入
SQL> insert into sales(prod_id,cust_id,time_id,quantity_sold)values(5,15,to_date('2017-8-01','yyyy-mm-dd'),103);
insert into sales(prod_id,cust_id,time_id,quantity_sold)values(5,15,to_date('2017-8-01','yyyy-mm-dd'),103)
ORA-01502: index 'LIJIAMAN.SALE_PK' or partition of such index is in unusable state

--數據無法刪除
SQL> delete from sales where prod_id = 3 ;
delete from sales where prod_id = 3
ORA-01502: index 'LIJIAMAN.SALE_PK' or partition of such index is in unusable state

--如果沒有更新到逐漸相關列,可以更新數據,否則不行
SQL> update sales set QUANTITY_SOLD = 105 where PROD_ID = 2;
1 row updated

SQL> update sales set QUANTITY_SOLD = 105 where cust_id = 12;
1 row updated

SQL> update sales set cust_id = 15 where PROD_ID = 2;
update sales set cust_id = 15 where PROD_ID = 2
ORA-01502: index 'LIJIAMAN.SALE_PK' or partition of such index is in unusable state

(6)接著重建唯一性索引”SALE_PK”

SQL> alter index lijiaman.sale_pk rebuild;

Index altered

對SALES表進行DML操作,可以正常進行

SQL> insert into sales(prod_id,cust_id,time_id,quantity_sold)values(5,15,to_date('2017-8-01','yyyy-mm-dd'),103);
1 row inserted

SQL> delete from sales where prod_id = 3 ;
1 row deleted

SQL> update sales set QUANTITY_SOLD = 105 where PROD_ID = 2;
1 row updated

SQL> update sales set QUANTITY_SOLD = 105 where cust_id = 12;
1 row updated

SQL> update sales set cust_id = 15 where PROD_ID = 2;
1 row updated

SQL> commit;
Commit complete

至此,我們可以大膽猜測:唯一性索引導致的ORA-01502問題。由於我們在創建索引的時候,並未直接創建唯一性索引,而是在創建主鍵約束的時候自動創建的唯一性索引,那麼到底是主鍵約束的問題,還是唯一性索引的問題?根據上面刪除分區前後約束狀態相同,而索引狀態不同,我覺得是索引的問題繼續求證。我們新建一個表,在上面直接創建唯一性索引,不創建任何約束。

創建表test01,錄入數據

SQL> select * from test01;

        ID NAME                        AGE
---------- -------------------- ----------
         1 lijiaman             
         2 gegeman                      25
         3 xiaoman                      26
         4 Lijiaman                     25

在“ID”列創建唯一性索引

SQL> create unique index inx_test01 on test01(id);

Index created


SQL> select table_owner,index_name,index_type,uniqueness,status
  2  from   user_indexes
  3  where  table_name = 'TEST01';

TABLE_OWNER                    INDEX_NAME                     INDEX_TYPE                  UNIQUENESS STATUS
------------------------------ ------------------------------ --------------------------- ---------- --------
LIJIAMAN                       INX_TEST01                     NORMAL                      UNIQUE     VALID

插入數據,沒有異常

SQL> insert into test01 values(5,'bokeyuan',22);

1 row inserted

接著將索引置為不可用狀態,然後往表裡面插入數據,出現了01502錯誤;

SQL> alter index lijiaman.inx_test01 unusable;     --將索引置為不可用狀態
Index altered

SQL> select table_owner,index_name,index_type,uniqueness,status
  2  from   user_indexes
  3  where  table_name = 'TEST01';

TABLE_OWNER                    INDEX_NAME                     INDEX_TYPE                  UNIQUENESS STATUS
------------------------------ ------------------------------ --------------------------- ---------- --------
LIJIAMAN                       INX_TEST01                     NORMAL                      UNIQUE     UNUSABLE


SQL> insert into test01 values(5,'bokeyuan',25);    --插入數據,發生ORA-01502錯誤
insert into test01 values(5,'bokeyuan',25)
ORA-01502: index 'LIJIAMAN.INX_TEST01' or partition of such index is in unusable state

至此可以明確的說:ORA-01512錯誤是由於唯一性索引失效導致的。

如何解決這個問題,前面給出了3種方案,只要選擇其中一種即可,不再模擬。


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 簡介 Hive 是基於 Hadoop 的一個數據倉庫工具,可以將結構化的數據文件 映射為一張資料庫表,並提供類 SQL 查詢功能。 本質是將 SQL 轉換為 MapReduce 程式。 Hive組件 用戶介面:包括 CLI、JDBC/ODBC、WebGUI。其中,CLI(command linein ...
  • 廣義上來說,Hadoop大數據平臺也可以看做是新一代的數據倉庫系統, 它也具有很多現代數據倉庫的特征,也被企業所廣泛使用。因為MPP架構的可擴展性,基於MPP的數據倉庫系統有時候也被劃分到大數據平臺類產品。 但是數據倉庫和Hadoop平臺還是有很多顯著的不同。針對不同的使用場景其發揮的作用和給用戶帶 ...
  • 問題是服務裡面mysql沒有啟動或者mysql服務丟失 解決辦法: 開始->運行->cmd,進到mysql安裝的bin目錄(以我的為例,我的安裝在D盤)D:\MySQL\bin>mysqld.exe -installService successfully installed. 這個時候刷新服務列表 ...
  • 採集目錄到HDFS 使用flume採集目錄需要啟動hdfs集群 spooldir source 監控指定目錄 如果目錄下有新文件產生 就採集走 註意!!! 此組件監控的目錄不能有同名的文件產生 一旦有重名文件:報錯 罷工 註意!!! 此組件監控的目錄不能有同名的文件產生 一旦有重名文件:報錯 罷工 ...
  • 概述 Flume 是 Cloudera 提供的一個高可用的,高可靠的,分散式的海量日誌採集、聚合和傳輸的軟體。 Flume 的核心是把數據從數據源(source)收集過來,再將收集到的數據送到指定的目的地(sink)。為了保證輸送的過程一定成功,在送到目的地(sink)之前,會先緩存數據(chann ...
  • 概述 序列化(Serialization)是指把結構化對象轉化為位元組流。 反序列化(Deserialization)是序列化的逆過程。把位元組流轉為結構化對象。 當要在進程間傳遞對象或持久化對象的時候,就需要序列化對象成位元組流,反之當要將接收到或從磁碟讀取的位元組流轉換為對象,就要進行反序列化。 Jav ...
  • 篇幅簡介 篇幅簡介 一、Msql數據類型 1、整型 tinyint, 占 1位元組 ,有符號: -128~127,無符號位 :0~255 smallint, 占 2位元組 ,有符號: -32768~32767無符號位 :0~65535 mediumint 占 3位元組 ,有符號: -8388608~838 ...
  • MapReduce 的輸入輸出 MapReduce 框架運轉在<key,value> 鍵值對上,也就是說,框架把作業的輸入看成是一組<key,value>鍵值對,同樣也產生一組<key,value>鍵值對作為作業的輸出,這兩組鍵值對可能是不同的。 一個 MapReduce 作業的輸入和輸出類型如下圖 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...