表扫描与索引扫描返回的行数不一致

某个应用最近总出现死锁,其中一些是因为报了索引和数据行存在不匹配的问题,MOS中有如下文档可以参考。


ORA-1499. Table/Index row count mismatch(文档 ID 563070.1)
现象
使用“validate structure cascade”分析表时报ORA-1499的错误,trace文件中包含“Table/Index row count mismatch”的错误信息。例如:
SQL> analyze table test validate structure cascade;
analyze table test validate structure cascade
*
ERROR at line 1:
ORA-01499: table/index cross reference failure - see trace file


trace文件中包含:
Table/Index row count mismatch
table 6559 : index 10000, 0
Index root = tsn: 6 rdba: 0x01400091
意味着扫描表返回6559行数据,索引扫描返回10000行数据。“Index root”是索引的段头信息。rdba: 0x01400091是相对于数据块地址的索引段头。他是十进制的20971665,Rfile#=5,Block#=145。

SQL> select dbms_utility.data_block_address_file(20971665) "Rfile#" ,dbms_utility.data_block_address_block(20971665) "Block#" from dual;
Rfile# Block#
---------- ----------
5 145


运行下面的查询明确关联的索引:

SQL>selectowner,segment_name,segment_type from dba_segments whereheader_file=5 andheader_block=145;

OWNER SEGMENT_NAMESEGMENT_TYPE
-----------------------------------------
SCOTTI_TEST INDEX
这种逻辑不一致性也能通过10g以上版本的ORA-600 [kdsgrp1]错误或低版本的ORA-600 [12700]错误来说明。

原因
这是一种表与索引之间的逻辑不一致。这种逻辑不一致通常是因为表上的高水位(HWM)出现了问题,全表扫描比索引扫描返回了更少的行。这种不一致性也可能是由于Oracle的defect或会引起IO丢失的OS/硬件问题导致的。

解决方案
可以通过下面的语句查询出全表扫描时未扫出的索引行:
select/*+INDEX_FFS(<tablename><indexnameidentifiedin2.1>)*/rowid
,dbms_rowid.ROWID_RELATIVE_FNO(rowid)relative_fno
,dbms_rowid.ROWID_BLOCK_NUMBER(rowid)block
from<tablename>
where<indexedcolumn>isnotnull
minus
select/*+FULL(<tablename>)*/rowid
,dbms_rowid.ROWID_RELATIVE_FNO(rowid)relative_fno
,dbms_rowid.ROWID_BLOCK_NUMBER(rowid)block
from<tablename>;

实例:
select/*+INDEX_FFS(TESTI_TEST)*/rowid
,dbms_rowid.ROWID_RELATIVE_FNO(rowid)relative_fno
,dbms_rowid.ROWID_BLOCK_NUMBER(rowid)block
fromtest
wherec2isnotnull
minus
select/*+FULL(TEST)*/rowid
,dbms_rowid.ROWID_RELATIVE_FNO(rowid)relative_fno
,dbms_rowid.ROWID_BLOCK_NUMBER(rowid)block
fromtest;

使用下面PLSQ中的索引,可以将全表扫描丢失的行存储到另一张表中:

droptabletest_copy;

createtabletest_copyasselect*fromtestwhere1=2;

declare
cursormissing_rowsis
select/*+INDEX_FFS(TESTI_TEST)*/rowidrid
fromtest
wherec2isnotnull
minus
select/*+FULL(TEST)*/rowidrid
fromtest;
begin
foriinmissing_rowsloop
insertintoTEST_COPY
select/*+ROWID(TEST)*/*fromTESTwhererowid=i.rid;
endloop;
end;
/

- 当索引返回的比表记录少时,重建索引可以解决这个问题。
- 当索引返回的比表记录多时,重建索引或执行虚拟insert插入该表的操作以提高HWM,可以最终解决这种逻辑错误。在以上这个案例中,修复了逻辑错误,但这些行也还是可能丢失了,因为是在执行这里提到的方法之前运行了上述PLSQL脚本。

如果从Oracle Support需要额外的帮助,请提供:
1. analyze语句分析的trace文件。

2. 第一个查询语句的结果。

3. dump基表段头产生的trace文件。
selectheader_file,header_block,tablespace_name fromdba_segments
whereowner=upper('&table_owner')andsegment_name=upper('&table_name');

altersystemdumpdatafile&header_fileblock&header_block;

trace文件用来明确HWM。
@ExamplefromablockdumpnotusingASSM(AutomaticSegmentSpaceManagement):
@
@ExtentControlHeader
@-----------------------------------------------------------------
@ExtentHeader::spare1:0spare2:0#extents:4#blocks:31
@lastmap0x00000000#maps:0offset:4128
@Highwater::0x014000d6ext#:3blk#:5extsize:8
@
@So,HWMislocatedatRDBA0x014000d6inextent_id=5andblock#=5inthatextent.

4. 这个查询结果可以明确索引多返回的行的区id:
selectrid,a.relative_fno,a.block,e.owner,e.segment_name,e.segment_type,e.extent_id,e.blocks
from(select/*+INDEX_FFS(<tablename><indexname>)*/rowidrid
,dbms_rowid.ROWID_RELATIVE_FNO(rowid)relative_fno
,dbms_rowid.ROWID_BLOCK_NUMBER(rowid)block
from<tableowner.tablename>
where<indexedcolumn>isnotnull
minus
select/*+FULL(<tablename>)*/rowidrid
,dbms_rowid.ROWID_RELATIVE_FNO(rowid)relative_fno
,dbms_rowid.ROWID_BLOCK_NUMBER(rowid)block
from<tableowner.tablename>
)a
,dba_extentse
wherea.relative_fno=e.relative_fno
ande.tablespace_name=upper('&tablespace_name')
andv.ts#=&tablespace_number
and(a.blockbetweene.block_idande.block_id+blocks-1);

注意:
- 以上SQL中请替换owner、表名、索引名和索引列。
- 表空间是上述步骤3提供的。
- 这个SQL查询提供了索引返回行位置的区extent。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值