近期接到客户电话,在统计某个业务表时的数据时,发现数据行数不一致,需要排查原因;查看用户的统计语句,分别是select *及select count(*),对数据库索引及执行计划有较多了解的可能一下就能想到,这两种写法可能会涉及到用索引、不用索引的问题;排查统计信息后,发现确实存在用索引及全表扫描问题,但是正常情况下这两种情况的行数也要一致;此次问题检查为表、索引不一致,通过重建索引处理后,数据查询一致。

但是在数据0行时查询非常慢,分析发现表存在严重高水位问题,0行数据时大小5GB多,因此进行表收缩后,查询速度恢复正常。

注意:重建索引时,ONLINE模式会从表中读取数据,详见MOS文档    处理 Oracle7/8/8i/9i/10g/11g 中的 Oracle 块损坏 (文档 ID 1526911.1)

  1. 不要使用“ALTER INDEX ..  REBUILD”命令重建损坏的非分区索引,这一点非常重要,因为此操作通常会尝试从包含坏块的现有索引段中构建新索引。 "ALTER INDEX ... REBUILD ONLINE" and "ALTER INDEX ... REBUILD PARTITION ..." 不会从旧索引段中构建新索引,因此可以使用。
1.查看统计信息
SQL> Select Count(*) From test002968.test11;

Execution Plan
----------------------------------------------------------
Plan hash value: 956078159
-----------------------------------------------------------------------------
| Id | Operation | Name | Rows | Cost (%CPU)| Time |
-----------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 2 (0)| 00:00:01 |
| 1 | SORT AGGREGATE | | 1 | | |
| 2 | INDEX FAST FULL SCAN| C_HY_JK_KEY | 1 | 2 (0)| 00:00:01 |
-----------------------------------------------------------------------------


SQL> Select * From test002968.test11;

no rows selected
Execution Plan
----------------------------------------------------------
Plan hash value: 2448501003
------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 815 | 186K (1)| 00:37:18 |
| 1 | TABLE ACCESS FULL| test11 | 1 | 815 | 186K (1)| 00:37:18 |
------------------------------------------------------------------------------------

2.重建索引后数据统计正常
SQL> alter index test002968.C_HY_JK_KEY REBUILD ONLINE;

Index altered.

SQL> Select Count(*) From test002968.test11;

COUNT(*)
----------
0

SQL> Select * From test002968.test11;

no rows selected


3.表高水位回收
SQL> select bytes/1024/1024 mb from dba_segments where owner='test002968' and segment_name='test11';

MB
----------
5383

SQL> alter table test11 enable row movement;

Table altered.

SQL> alter table test11 SHRINK SPACE CASCADE;

Table altered.

SQL> alter table test11 disable row movement;

Table altered.

SQL> select bytes/1024/1024 mb from dba_segments where owner='test002968' and segment_name='test11';

MB
----------
.0625