解决 ORA-14098 分区交换
       索引不匹配错误




         by Maclean.liu
               liu.maclean@gmail.com
           www.oracledatabase12g.com

o
w
n
e
r

=

'
&
O
W
N
E
R
1
'
About Me

l Email:liu.maclean@gmail.com
l Blog:www.oracledatabase12g.com
l Oracle Certified Database Administrator Master 10g
and 11g
l Over 6 years experience with Oracle DBA technology
l Over 7 years experience with Linux technology
l Member Independent Oracle Users Group
l Member All China Users Group
l Presents for advanced Oracle topics: RAC,
DataGuard, Performance Tuning and Oracle Internal.
上周在客户一套 BRM 系统上执行分区交换 Exchange Partition 操作的时候出现了 ORA-14098
错误,该错误是由于分区表上的 LOCAL 分区索引与非分区表上的索引不匹配造成的,我们
来看一下这个错误:



[oracle@rh2 ~]$ oerr ora 14098
14098, 00000, "index mismatch for tables in ALTER TABLE EXCHANGE PARTITION"
// *Cause: The two tables specified in the EXCHANGE have indexes which are
//          not equivalent
// *Action: Ensure that the indexes for the two tables have indexes which
//          follow this rule
//          For every non partitioned index for the non partitioned table,
//          there has to be an identical LOCAL index on the partitioned
//          table and vice versa. By identical, the column position, type
//          and size have to be the same.

SQL> ALTER TABLE sales EXCHANGE PARTITION SALES_Q4_2003 with
table SALES_TMP INCLUDING INDEXES WITH VALIDATION UPDATE GLOBAL INDEXES;

ALTER TABLE sales EXCHANGE PARTITION SALES_Q4_2003 with
table SALES_TMP INCLUDING INDEXES WITH VALIDATION UPDATE GLOBAL INDEXES
                                *
ERROR at line 1:
ORA-14098: index mismatch for tables in ALTER TABLE EXCHANGE PARTITION




如果表上有很多的索引,以至于你无法确定到底是哪个索引引发了 ORA-14098 错误,那么
我们可以通过 trace 的方式来协助定位到具体的索引:



SQL>   select * from v$version;

BANNER
----------------------------------------------------------------
Oracle Database 10g Enterprise Edition Release 10.2.0.4.0 - 64bi
PL/SQL Release 10.2.0.4.0 - Production
CORE    10.2.0.4.0      Production
TNS for Linux: Version 10.2.0.4.0 - Production
NLSRTL Version 10.2.0.4.0 - Production

SQL> select * from global_name;

GLOBAL_NAME
--------------------------------------------------------------------------------
www.oracledatabase12g.com

SQL> alter session set max_dump_file_size = unlimited;
Session altered.
SQL> alter session set events '10046 trace name context forever, level 12';
Session altered.

SQL> alter session set events '14098 trace name errorstack forever, level 4';
Session altered.

##SQL> alter system flush buffer_cache;
System altered.

Rerun Exchange Partition DDL

SQL> ALTER TABLE sales EXCHANGE PARTITION SALES_Q4_2003 with table SALES_TMP
INCLUDING INDEXES WITH VALIDATION UPDATE GLOBAL INDEXES;

ALTER TABLE sales EXCHANGE PARTITION SALES_Q4_2003 with table SALES_TMP
INCLUDING INDEXES WITH VALIDATION UPDATE GLOBAL INDEXES
                                *
ERROR at line 1:
ORA-14098: index mismatch for tables in ALTER TABLE EXCHANGE PARTITION

11g 中直接查询 v$diag_info 就可以得到 trace 的路径,10g 执行 gettracename.sql

SELECT     d.VALUE
    || '/'
    || LOWER (RTRIM (i.INSTANCE, CHR (0)))
    || '_ora_'
    || p.spid
    || '.trc' trace_file_name
 FROM (SELECT p.spid
      FROM v$mystat m, v$session s, v$process p
     WHERE m.statistic# = 1 AND s.SID = m.SID AND p.addr = s.paddr) p,
    (SELECT t.INSTANCE
      FROM v$thread t, v$parameter v
     WHERE v.NAME = 'thread'
       AND (v.VALUE = 0 OR t.thread# = TO_NUMBER (v.VALUE))) i,
    (SELECT VALUE
      FROM v$parameter
     WHERE NAME = 'user_dump_dest') d;

TRACE_FILE_NAME
--------------------------------------------------------------------------------
/s01/admin/G10R2/udump/g10r2_ora_17749.trc

==========================10046/errorstack trace
contents========================
PARSING IN CURSOR #1 len=127 dep=0 uid=64 oct=15 lid=64 tim=1277655207436065
hv=1207961095 ad='9098f018'
ALTER TABLE sales EXCHANGE PARTITION SALES_Q4_2003 with table SALES_TMP
INCLUDING INDEXES WITH VALIDATION UPDATE GLOBAL INDEXES
END OF STMT
PARSE #1:c=0,e=1145,p=0,cr=0,cu=0,mis=1,r=0,dep=0,og=1,tim=1277655207436059
BINDS #1:
STAT #2 id=2 cnt=0 pid=1 pos=1 obj=98001 op='INDEX FULL SCAN SALES_UNID_TMP
(cr=1 pr=0 pw=0 time=39 us)'
*** 2011-06-17 21:55:32.417
ksedmp: internal or fatal error
ORA-14098: index mismatch for tables in ALTER TABLE EXCHANGE PARTITION
Current SQL statement for this session:
ALTER TABLE sales EXCHANGE PARTITION SALES_Q4_2003 with table SALES_TMP
INCLUDING INDEXES WITH VALIDATION UPDATE GLOBAL INDEXES

我们可以在 trace 中看到在出现 ORA-14098 错误前,正在对索引 SALES_UNID_TMP 的 Fast Full Scan




除了通过 10046/errorstack 的 trace 信息诊断外,更多的问题可以直接从 DDL 语句中发现,在
以上示例中非分区表的 DDL 语句:
-- Create table
create table SALES_TMP
(
  UNI_ID        NUMBER NOT NULL,
  PROD_ID       NUMBER not null,
  CUST_ID       NUMBER not null,
  TIME_ID       DATE not null,
  CHANNEL_ID    NUMBER not null,
  PROMO_ID      NUMBER not null,
  QUANTITY_SOLD NUMBER(10,2) not null,
  AMOUNT_SOLD   NUMBER(10,2) not null
);

create index SALES_CHANNEL_TMP       ON SALES_TMP (CHANNEL_ID) ;
create index SALES_CUST_TMP          ON SALES_TMP (CUST_ID)    ;
create index SALES_UNID_TMP          ON SALES_TMP (UNI_ID,TIME_ID);   --注意细节
该索引是非 UNIQUE 的
create index SALES_PROD_TMP          ON SALES_TMP (PROD_ID)     ;
create index SALES_PROMO_TMP         ON SALES_TMP (PROMO_ID)    ;
create index SALES_TIME_TMP          ON SALES_TMP (TIME_ID)     ;


下为分区表的 DDL 语句:
-- Create table
create table SALES
(
  UNI_ID        NUMBER NOT NULL,
  PROD_ID       NUMBER not null,
  CUST_ID       NUMBER not null,
  TIME_ID       DATE not null,
  CHANNEL_ID    NUMBER not null,
  PROMO_ID      NUMBER not null,
  QUANTITY_SOLD NUMBER(10,2) not null,
  AMOUNT_SOLD   NUMBER(10,2) not null
)
partition by range (TIME_ID)
...............

create index SALES_CHANNEL       ON SALES (CHANNEL_ID) LOCAL;
create index SALES_CUST          ON SALES (CUST_ID)    LOCAL;
create UNIQUE index SALES_UNID   ON SALES (UNI_ID,TIME_ID) LOCAL;     -- 对应的
索引是 UNIQUE 的
create index SALES_PROD          ON SALES (PROD_ID)    LOCAL;
create index SALES_PROMO         ON SALES (PROMO_ID)   LOCAL;
create index SALES_TIME          ON SALES (TIME_ID)    LOCAL;
解决 ORA-14098 错误的要点是要找出引发错误的原因。当我们交换分区的时候,我们要确
保所有交换表上的索引和分区表上的本地索引匹配。这意味 着如果在分区表上有 N 个
LOCAL INDEXES,那么在交换表上就应当有 N 个等价的索引。这里的等价要求存在映射关
系的 2 个索引,在列的位置、类型、大小及 UNIQUE/NON- UNIQUE 都要一致。


可以利用如下 SQL 语句来找出分区表和交换表上索引的差异:



set linesize 160 pagesize 1400

col   TABLE_NAME for a30
col   INDEX_NAME for a30
col   COLUMN_NAME for a30
col   COLUMN_POSITION for 99
col   COLUMN_LENGTH for 99
col   CHAR_LENGTH for 99
col   DESCEND for a4

Select TABLE_NAME,INDEX_NAME, COLUMN_NAME,COLUMN_POSITION, COLUMN_LENGTH,
CHAR_LENGTH, DESCEND
FROM SYS.DBA_IND_COLUMNS DICN
WHERE INDEX_OWNER = '&own'
 and DICN.TABLE_NAME in ('&TABNAME1','&TABNAME2')
ORDER BY INDEX_NAME, COLUMN_POSITION
/

select TABLE_NAME, INDEX_NAME, INDEX_TYPE, UNIQUENESS, PARTITIONED
  from dba_indexes
 where owner='&OWNER'
   and TABLE_NAME in ('&TABNAME1', '&TABNAME2')
 order by index_name
/
也可以使用 Toad 的 Single Schema Object Compare 功能来对比检验索引:




对于存在主键的分区表,可以在主键上以 DISABLE VALIDATE 方式创建 unique constraint 约
束,以代替全局的主键索引。若交换表(Exchange Table)上存在主键索引的话,那么建议在交
换前暂时将该索引 drop 掉,待交换完成后再重建。

如果实在无法解决该 ORA-14098 错误,那么可以尝试使用 EXCLUDING INDEXES 子句以跳
过索引维护,而在交换完成后重建相关失效索引。




© 2011, www.oracledatabase12g.com. 版权所有.文章允许转载,但必须以链接方式注明源地址,
否则追求法律责任.

解决Ora 14098分区交换索引不匹配错误

  • 1.
    解决 ORA-14098 分区交换 索引不匹配错误 by Maclean.liu liu.maclean@gmail.com www.oracledatabase12g.com o w n e r = ' & O W N E R 1 '
  • 2.
    About Me l Email:liu.maclean@gmail.com lBlog:www.oracledatabase12g.com l Oracle Certified Database Administrator Master 10g and 11g l Over 6 years experience with Oracle DBA technology l Over 7 years experience with Linux technology l Member Independent Oracle Users Group l Member All China Users Group l Presents for advanced Oracle topics: RAC, DataGuard, Performance Tuning and Oracle Internal.
  • 3.
    上周在客户一套 BRM 系统上执行分区交换Exchange Partition 操作的时候出现了 ORA-14098 错误,该错误是由于分区表上的 LOCAL 分区索引与非分区表上的索引不匹配造成的,我们 来看一下这个错误: [oracle@rh2 ~]$ oerr ora 14098 14098, 00000, "index mismatch for tables in ALTER TABLE EXCHANGE PARTITION" // *Cause: The two tables specified in the EXCHANGE have indexes which are // not equivalent // *Action: Ensure that the indexes for the two tables have indexes which // follow this rule // For every non partitioned index for the non partitioned table, // there has to be an identical LOCAL index on the partitioned // table and vice versa. By identical, the column position, type // and size have to be the same. SQL> ALTER TABLE sales EXCHANGE PARTITION SALES_Q4_2003 with table SALES_TMP INCLUDING INDEXES WITH VALIDATION UPDATE GLOBAL INDEXES; ALTER TABLE sales EXCHANGE PARTITION SALES_Q4_2003 with table SALES_TMP INCLUDING INDEXES WITH VALIDATION UPDATE GLOBAL INDEXES * ERROR at line 1: ORA-14098: index mismatch for tables in ALTER TABLE EXCHANGE PARTITION 如果表上有很多的索引,以至于你无法确定到底是哪个索引引发了 ORA-14098 错误,那么 我们可以通过 trace 的方式来协助定位到具体的索引: SQL> select * from v$version; BANNER ---------------------------------------------------------------- Oracle Database 10g Enterprise Edition Release 10.2.0.4.0 - 64bi PL/SQL Release 10.2.0.4.0 - Production CORE 10.2.0.4.0 Production TNS for Linux: Version 10.2.0.4.0 - Production NLSRTL Version 10.2.0.4.0 - Production SQL> select * from global_name; GLOBAL_NAME -------------------------------------------------------------------------------- www.oracledatabase12g.com SQL> alter session set max_dump_file_size = unlimited; Session altered.
  • 4.
    SQL> alter sessionset events '10046 trace name context forever, level 12'; Session altered. SQL> alter session set events '14098 trace name errorstack forever, level 4'; Session altered. ##SQL> alter system flush buffer_cache; System altered. Rerun Exchange Partition DDL SQL> ALTER TABLE sales EXCHANGE PARTITION SALES_Q4_2003 with table SALES_TMP INCLUDING INDEXES WITH VALIDATION UPDATE GLOBAL INDEXES; ALTER TABLE sales EXCHANGE PARTITION SALES_Q4_2003 with table SALES_TMP INCLUDING INDEXES WITH VALIDATION UPDATE GLOBAL INDEXES * ERROR at line 1: ORA-14098: index mismatch for tables in ALTER TABLE EXCHANGE PARTITION 11g 中直接查询 v$diag_info 就可以得到 trace 的路径,10g 执行 gettracename.sql SELECT d.VALUE || '/' || LOWER (RTRIM (i.INSTANCE, CHR (0))) || '_ora_' || p.spid || '.trc' trace_file_name FROM (SELECT p.spid FROM v$mystat m, v$session s, v$process p WHERE m.statistic# = 1 AND s.SID = m.SID AND p.addr = s.paddr) p, (SELECT t.INSTANCE FROM v$thread t, v$parameter v WHERE v.NAME = 'thread' AND (v.VALUE = 0 OR t.thread# = TO_NUMBER (v.VALUE))) i, (SELECT VALUE FROM v$parameter WHERE NAME = 'user_dump_dest') d; TRACE_FILE_NAME -------------------------------------------------------------------------------- /s01/admin/G10R2/udump/g10r2_ora_17749.trc ==========================10046/errorstack trace contents======================== PARSING IN CURSOR #1 len=127 dep=0 uid=64 oct=15 lid=64 tim=1277655207436065 hv=1207961095 ad='9098f018' ALTER TABLE sales EXCHANGE PARTITION SALES_Q4_2003 with table SALES_TMP INCLUDING INDEXES WITH VALIDATION UPDATE GLOBAL INDEXES END OF STMT PARSE #1:c=0,e=1145,p=0,cr=0,cu=0,mis=1,r=0,dep=0,og=1,tim=1277655207436059 BINDS #1: STAT #2 id=2 cnt=0 pid=1 pos=1 obj=98001 op='INDEX FULL SCAN SALES_UNID_TMP (cr=1 pr=0 pw=0 time=39 us)' *** 2011-06-17 21:55:32.417 ksedmp: internal or fatal error ORA-14098: index mismatch for tables in ALTER TABLE EXCHANGE PARTITION Current SQL statement for this session: ALTER TABLE sales EXCHANGE PARTITION SALES_Q4_2003 with table SALES_TMP
  • 5.
    INCLUDING INDEXES WITHVALIDATION UPDATE GLOBAL INDEXES 我们可以在 trace 中看到在出现 ORA-14098 错误前,正在对索引 SALES_UNID_TMP 的 Fast Full Scan 除了通过 10046/errorstack 的 trace 信息诊断外,更多的问题可以直接从 DDL 语句中发现,在 以上示例中非分区表的 DDL 语句: -- Create table create table SALES_TMP ( UNI_ID NUMBER NOT NULL, PROD_ID NUMBER not null, CUST_ID NUMBER not null, TIME_ID DATE not null, CHANNEL_ID NUMBER not null, PROMO_ID NUMBER not null, QUANTITY_SOLD NUMBER(10,2) not null, AMOUNT_SOLD NUMBER(10,2) not null ); create index SALES_CHANNEL_TMP ON SALES_TMP (CHANNEL_ID) ; create index SALES_CUST_TMP ON SALES_TMP (CUST_ID) ; create index SALES_UNID_TMP ON SALES_TMP (UNI_ID,TIME_ID); --注意细节 该索引是非 UNIQUE 的 create index SALES_PROD_TMP ON SALES_TMP (PROD_ID) ; create index SALES_PROMO_TMP ON SALES_TMP (PROMO_ID) ; create index SALES_TIME_TMP ON SALES_TMP (TIME_ID) ; 下为分区表的 DDL 语句: -- Create table create table SALES ( UNI_ID NUMBER NOT NULL, PROD_ID NUMBER not null, CUST_ID NUMBER not null, TIME_ID DATE not null, CHANNEL_ID NUMBER not null, PROMO_ID NUMBER not null, QUANTITY_SOLD NUMBER(10,2) not null, AMOUNT_SOLD NUMBER(10,2) not null ) partition by range (TIME_ID) ............... create index SALES_CHANNEL ON SALES (CHANNEL_ID) LOCAL; create index SALES_CUST ON SALES (CUST_ID) LOCAL; create UNIQUE index SALES_UNID ON SALES (UNI_ID,TIME_ID) LOCAL; -- 对应的 索引是 UNIQUE 的 create index SALES_PROD ON SALES (PROD_ID) LOCAL; create index SALES_PROMO ON SALES (PROMO_ID) LOCAL; create index SALES_TIME ON SALES (TIME_ID) LOCAL;
  • 6.
    解决 ORA-14098 错误的要点是要找出引发错误的原因。当我们交换分区的时候,我们要确 保所有交换表上的索引和分区表上的本地索引匹配。这意味着如果在分区表上有 N 个 LOCAL INDEXES,那么在交换表上就应当有 N 个等价的索引。这里的等价要求存在映射关 系的 2 个索引,在列的位置、类型、大小及 UNIQUE/NON- UNIQUE 都要一致。 可以利用如下 SQL 语句来找出分区表和交换表上索引的差异: set linesize 160 pagesize 1400 col TABLE_NAME for a30 col INDEX_NAME for a30 col COLUMN_NAME for a30 col COLUMN_POSITION for 99 col COLUMN_LENGTH for 99 col CHAR_LENGTH for 99 col DESCEND for a4 Select TABLE_NAME,INDEX_NAME, COLUMN_NAME,COLUMN_POSITION, COLUMN_LENGTH, CHAR_LENGTH, DESCEND FROM SYS.DBA_IND_COLUMNS DICN WHERE INDEX_OWNER = '&own' and DICN.TABLE_NAME in ('&TABNAME1','&TABNAME2') ORDER BY INDEX_NAME, COLUMN_POSITION / select TABLE_NAME, INDEX_NAME, INDEX_TYPE, UNIQUENESS, PARTITIONED from dba_indexes where owner='&OWNER' and TABLE_NAME in ('&TABNAME1', '&TABNAME2') order by index_name /
  • 7.
    也可以使用 Toad 的Single Schema Object Compare 功能来对比检验索引: 对于存在主键的分区表,可以在主键上以 DISABLE VALIDATE 方式创建 unique constraint 约 束,以代替全局的主键索引。若交换表(Exchange Table)上存在主键索引的话,那么建议在交 换前暂时将该索引 drop 掉,待交换完成后再重建。 如果实在无法解决该 ORA-14098 错误,那么可以尝试使用 EXCLUDING INDEXES 子句以跳 过索引维护,而在交换完成后重建相关失效索引。 © 2011, www.oracledatabase12g.com. 版权所有.文章允许转载,但必须以链接方式注明源地址, 否则追求法律责任.