天天看點

續《表掃描與索引掃描傳回的行數不一緻》

上篇文章主要介紹了如何從分析表得到的報錯,以及trace中的資訊,判斷表傳回的記錄與索引傳回記錄不一緻時的處理方式。下面這篇文章則介紹了針對ORA-1499進行問題排查的一些基本方法。

OERR: ORA-1499 table/Index Cross Reference Failure - see trace file (文檔 ID 1499.1)

Error: ORA 1499

Text: table/Index Cross Reference Failure - see trace file

-------------------------------------------------------------------------------

Cause:  An error occurred when validating an index or a table using the

        ANALYZE command.

        One or more entries does not point to the appropriate cross-reference.

Action: Check the trace file for more descriptive messages about the problem.

        Correct these errors.

ORA-1499的錯誤是通過“"ANALIZE TABLE|CLUSTER <name> VALIDATE STRUCTURE CASCADE”分析得出的,它的含義是表或聚類和索引之間存在不一緻性,具體來講是索引鍵值未出現在索引中,或者相反。

trace檔案中包含:

<description>: tsn: <tablespace number> rdba: <relative dba>

description有以下值:

"row not found in index" 

"Table/Index row count mismatch"

"row mismatch in index dba"

"Table row count/Bitmap index bit count mismatch"

"kdavls: kdcchk returns %d when checking cluster dba 0x%08lx objn %d\n"

tsn:    Tablespace Number表示的是索引存儲的表空間編号。

rdba: 是索引段頭相對于資料塊的存儲位址。

SQL> analyze table DEPT validate structure cascade;

analyze table case7 validate structure cascade

*

ERROR at line 1:

ORA-01499: table/index cross reference failure - see trace file

trace檔案的執行個體:

row not found in index tsn: 5 rdba: 0x02c00061

哪些索引受影響?

包含ORA-1499的trace檔案提供了與索引相關的段頭rdba。查詢dba_segments來明确索引:

SELECT owner, segment_name, segment_type, partition_name

FROM   DBA_SEGMENTS

WHERE  header_file = (SELECT file#

                                          FROM   v$datafile

                                          WHERE  rfile# = dbms_utility.data_block_address_file(to_number('&rdba','XXXXXXXX'))

                                          AND  ts#= &tsn)

                 AND header_block = dbms_utility.data_block_address_block(to_number('&rdba','XXXXXXXX'));

&rdba值應該是删除’0x‘的十六進制的rdba,tsn是表空間編号。

例如:

FROM DBA_SEGMENTS

WHERE header_file = (SELECT file#

                                         FROM   v$datafile

                                     WHERE  rfile# = dbms_utility.data_block_address_file(to_number('02c00061','XXXXXXXX'))

                                        AND  ts#= 5)

                AND header_block = dbms_utility.data_block_address_block(to_number('02c00061','XXXXXXXX'));

明确受影響的鍵值:

如果需要明确所有受影響的鍵,需要運作一次全表掃描和索引掃描:

在表中但未在索引的行:

SELECT /*+ FULL(t1) */ rowid, <indexed column list>

FROM   <Table name> t1

MINUS

SELECT /*+ index(t <Index name>) */ rowid, <indexed column list>

FROM   <Table name> t;

在索引中但未在表中的行:

FROM   <Table name> t

FROM  <Table name> t1;

執行個體:

表名 = DEPT,索引名 = I_DEPT1,在索引I_DEPT1中的索引列:DEPTNO,DNAME.

SELECT /*+ FULL(t1) */ rowid, deptno, dname

FROM   dept t1

SELECT /*+ index(t I_DEPT1) */ rowid, deptno, dname

FROM   dept t;

確定查詢語句的執行計劃使用受影響的索引,例如I_DEPT1會展示在執行計劃中。查詢未使用索引的原因之一是因為索引列定義為允許NULL值。如果是這樣,可以添加一個where子句,例如:where deptno is not null。

導緻這種問題的根本原因就是表和索引之間的不一緻,可能是由于Oracle的defect産生,或者Oracle外部問題,例如IO丢失。硬體或OS子系統問題可能導緻IO丢失寫入。如果出現IO丢失,包含表或索引的塊修改操作就可能不會寫入Oracle的資料檔案中,引起鍵缺失。解決方法可以參考上一篇文章《表掃描與索引掃描傳回的行數不一緻》。當出現表和索引之間不一緻的情況,即表中的行不在索引中,删除并重建索引是常用的一種合适方法。