业务侧说有报“ORA-08103: object no longer exists”的错误,但是查看后对应的表存在,比较巧的是这个表是分区表,所以推测是在此期间对分区表的DDL(drop partition)导致的问题。
1、测试数据的准备
create table t_list_partition(a int,b int)
partition by list(a)
(partition p1 values (1),
partition p2 values (2)
);
SQL> declare
2 -- Local variables here
3 i integer;
4 begin
5 i:=200001;
6 WHILE i <= 1000000
7 LOOP
8 insert into t_list_partition (a,b) VALUES(1,i);
9 i := i+1;
10 END LOOP;
11 if mod(i,20000)=0 then
12 commit;
13 end if;
14 commit;
15 end;
16 /
PL/SQL procedure successfully completed
SQL>
SQL> declare
2 -- Local variables here
3 i integer;
4 begin
5 i:=0;
6 WHILE i <= 1000000
7 LOOP
8 insert into t_list_partition (a,b) VALUES(1,i);
9 i := i+1;
10 END LOOP;
11 if mod(i,20000)=0 then
12 commit;
13 end if;
14 commit;
15 end;
16 /
PL/SQL procedure successfully completed
SQL>
SQL> declare
2 -- Local variables here
3 i integer;
4 begin
5 i:=0;
6 WHILE i <= 10000000
7 LOOP
8 insert into t_list_partition (a,b) VALUES(2,i);
9 i := i+1;
10 END LOOP;
11 if mod(i,20000)=0 then
12 commit;
13 end if;
14 commit;
15 end;
16 /
PL/SQL procedure successfully completed
SQL> insert into t_list_partition select * from t_list_partition;
22000004 rows inserted
SQL> commit;
Commit complete
SQL>
SQL> insert into t_list_partition select * from t_list_partition;
44000008 rows inserted
SQL> commit;
Commit complete
2、测试:
2.1场景1:
session1中操作的数据包含t_list_partition P1和 P2中的数据,drop p2,session中的SQL报错
session1:
操作的数据包含t_list_partition P1和 P2中的数据
SQL> insert into t_csp select * from t_list_partition where (b>9000000 and b<9000000) or (b>900000 and b<8000000);
insert into t_csp select * from t_list_partition where (b>9000000 and b<9000000) or (b>900000 and b<8000000)
session 2中:在session1执行后还未执行完之前,在session中2执行
SQL> alter table t_list_partition drop partition P2;
Table altered
session1:session2执行后,session1中报错
这时session1中的sql报错:
ORA-08103: object no longer exists
2.2场景2:
session1中要读取的数据只包含P1,不包含P2,但是分区字段限制在P1分区,drop partition P2对session1无影响
session1:
SQL> insert into t_csp select * from t_list_partition where a=1 and ((b>9 and b<=300000) or (b>500000 and b<1000000));
38399520 rows inserted
SQL> commit;
Commit complete
SQL>
session2:
SQL> alter table t_list_partition drop partition P2;
Table altered
2.3场景3:
session1中sql语句只涉及P2分区的数据,但是不带分区字段的限制,drop partition P2对session1报错
重新组织数据:
SQL> select max(b) from t_list_partition where a=2;
MAX(B)
----------
100000000
SQL> select max(b) from t_list_partition where a=1;
MAX(B)
----------
1000000
session1:sql语句只涉及P2分区的数据,但是不带分区字段的限制
SQL> insert into t_csp select * from t_list_partition where (b>1100000 and b<9990000) or (b>11100000 and b<799990000);
session2 :在session1执行后还未执行完之前,在session中2执行
SQL> alter table t_list_partition drop partition P2;
Table altered
session1:报错
insert into t_csp select * from t_list_partition where (b>1100000 and b<9990000) or (b>11100000 and b<799990000)
ORA-08103: object no longer exists
2.4场景4:
session1中sql语句的b值只包含P1分区的数据,不包含p2分区的数据,但是不带分区字段的限制,drop partition P2对session1报错
P1中的b指是从0到1000000,p2分区中的b值都是大于1000000
SQL> select count(*) from t_list_partition3 where a=2 and b<1000000;
COUNT(*)
----------
0
session1:操作中的b值只包含P1分区的数据,不包含p2分区的数据
SQL> insert into t_csp select * from t_list_partition4 where (b>5 and b<200000) or (b>300000 and b<980000);
session2:session1的sql执行后,在session2中执行如下sql
SQL> alter table t_list_partition4 drop partition P2;
Table altered
session1:报错
insert into t_csp select * from t_list_partition4 where (b>5 and b<200000) or (b>300000 and b<980000)
ORA-08103: object no longer exists
综上所述,如果分区字段上有需要drop分区的操作(比如定时的把历史数据迁移走后,删除对应的分区),最好是此分区表上所有的SQL语句都要带上分区字段的限制(避免查询在这期间要drop的分区),在业务进行期间且不要删除业务需要用的分区。