(一)问题:

最近在做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错误;

这里记录一下哪些操作会导致索引失效:

                                                              图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种方案,只要选择其中一种即可,不再模拟。

Oracle分区表删除分区引发错误ORA-01502: 索引或这类索引的分区处于不可用状态的更多相关文章

  1. Oracle异常处理——ORA-01502:索引或这类索引的分区处于不可用状态

    Oracle异常处理--ORA-01502:索引或这类索引的分区处于不可用状态参考自:https://www.cnblogs.com/lijiaman/p/9277149.html 1.原因分析经过查 ...

  2. ORA-01502: 索引或这类索引的分区处于不可用状态

    ORA-01502: 索引或这类索引的分区处于不可用状态 原因: 出现这个问题,可能有人move过表,或者disable 过索引.1. alter table xxxxxx move tablespa ...

  3. 索引 'GXHRCS.PK_A253' 或这类索引的分区处于不可用状态

    ORA-01502: 索引 'GXHRCS.PK_A253' 或这类索引的分区处于不可用状态 http://blog.sina.com.cn/s/blog_7ab8d2720101ozw6.html ...

  4. ORACLE分区表删除分区数据

    --全删除 ALTER TABLE tableName DROP PARTITION partionName UPDATE GLOBAL INDEXES; --清数据 ALTER TABLE tabl ...

  5. Oracle分区表删除分区数据时导致索引失效解决

    https://blog.csdn.net/e_wsq/article/details/80896258

  6. Oracle创建删除用户,角色,表空间,导入导出数据库命令总结(转载)

    无意间看到一篇文章,觉得对于ORACLE的新手很实用,特转载,原文出处这里 说明:在创建数据库时输入的密码,是修改系统默认的密码,以system和sysman等系统默认身份登录时要输入的密码就是修改后 ...

  7. Oracle 分区表的新增、修改、删除、合并。普通表转分区表方法

    一. 分区表理论知识 Oracle提供了分区技术以支持VLDB(Very Large DataBase).分区表通过对分区列的判断,把分区列不同的记录,放到不同的分区中.分区完全对应用透明. Orac ...

  8. oracle分区表的建立方法(包含已经存在的表要分区)分享,非常好

    非原创 Oracle提供了分区技术以支持VLDB(Very Large DataBase).分区表通过对分区列的判断,把分区列不同的记录,放到不同的分区中.分区完全对应用透明. Oracle的分区表可 ...

  9. 【三思笔记】 全面学习Oracle分区表及分区索引

    [三思笔记]全面学习Oracle分区表及分区索引 2008-04-15 关于分区表和分区索引(About PartitionedTables and Indexes) 对于 10gR2 而言,基本上可 ...

随机推荐

  1. cocos-creator 脚本逻辑-2

    1.预制体 1)节点操作 Cc.find(‘node-1’) 获取节点 全局事件 作用于 canvas this.node.destroy() 删除节点(从内存中删除) 添加删除获取节点或组件 let ...

  2. 用iframe踩的坑

    1.无法监控iframe加载成功与否 经测试,火狐及chorme都不支持onerror事件,而且,不管iframe加载是否成功,都会触发onload事件. 1)通过postmessage消息提示是否加 ...

  3. openlayers跨域设置后出现http status 500错误

    最近需要弄一下地理信息系统,用到openlayers和geoserver.在解决跨域的时候出现如下问题.求解决方案啊. 问题如下: 附:已经安装了python27,环境变量path中也添加了:c:\P ...

  4. 常见的浏览器兼容性问题与解决方案——CSS篇

    1.不同的浏览器的标签默认的外补丁和内补丁不同 问题症状:随便写几个标签,不加样式控制的情况下,各自的margin和padding差异较大. 碰到频率:100% 解决方案:初始化CSS的默认样式,*{ ...

  5. 记重回IT行业的面试

    问点: 0,梳理一个前端知识框架 1,jQuery的理解 2,仿某网站首页,除了download,显示新优化地方 3,文档模型(DOM) 事件流 事件处理程序 事件类型 例如阻止冒泡的方法 4,前端跟 ...

  6. 【Leetcode】【Hard】Search in Rotated Sorted Array

    Suppose a sorted array is rotated at some pivot unknown to you beforehand. (i.e., 0 1 2 4 5 6 7 migh ...

  7. 根据ip抓 包

    tcpdump -i any -s 0  host 101.81.134.53 -c 1000  -w ./zhj.cap

  8. C++的extern关键字

    extern是一个声明,不是一个定义,A模块想应用B模块的一个函数或者变量,A模块包含B模块的头文件,并且在变量或者头文件前,加 extern,虽然编译的时候,找不到模块的定义,但是在连接的时候,会在 ...

  9. 二阶SQL注入理解与体会

    一:SQL注入分类 SQL注入一般分为两类:一阶SQL注入(普通SQL注入),二阶SQL注入 二:二者进行比较 0x01:一阶SQL注入: 1:一阶SQL注入发生在一个HTTP请求和响应中,对系统的攻 ...

  10. 沉淀,再出发——在Hadoop集群的基础上搭建Spark

    在Hadoop集群的基础上搭建Spark 一.环境准备 在搭建Spark环境之前必须搭建Hadoop平台,尽管以前的一些博客上说在单机的环境下使用本地FS不用搭建Hadoop集群,可是在新版spark ...