对index直接rebuild的时候一定会是index fast full scan吗?
呵呵,当然不是,我们来看一个反例:
SQL> create table testindex
2 (pvalue varchar2(1),
3 pkey number)
4 partition by range (pkey)
5 (
6 partition testindex_part_1 values less than (2)
7 tablespace TESTTBS1,
8 partition testindex_part_2 values less than (3)
9 tablespace TESTTBS2
10 )
11 enable row movement;
Table created
SQL> insert into testindex values('a',1);
1 row inserted
SQL> insert into testindex values('b',1);
1 row inserted
SQL> insert into testindex values('c',2);
1 row inserted
SQL> insert into testindex values('d',2);
1 row inserted
SQL> commit;
Commit complete
SQL> create index idx_testindex_pvalue on testindex(pvalue);
Index created
我把pvalue='a'的那条记录的pkey由1改为2,这时候因为上述分区在不同的表空间下,所以索引idx_testindex_pvalue中对应于键值为'a'的global rowid一定会变。
好了,我们来验证一下:
未改之前:
row#0[8017] flag: -----, lock: 0
col 0; len 1; (1): 61
col 1; len 10; (10): 00 01 50 dd 21 80 07 99 00 00
row#1[8002] flag: -----, lock: 0
col 0; len 1; (1): 62
col 1; len 10; (10): 00 01 50 dd 21 80 07 99 00 01
row#2[7987] flag: -----, lock: 0
col 0; len 1; (1): 63
col 1; len 10; (10): 00 01 50 de 22 00 11 19 00 00
row#3[7972] flag: -----, lock: 0
col 0; len 1; (1): 64
col 1; len 10; (10): 00 01 50 de 22 00 11 19 00 01
SQL> update testindex set pkey=2 where pvalue='a';
1 row updated
SQL> commit;
Commit complete
SQL> select * from testindex;
PVALUE PKEY
------ ----------
b 1
c 2
d 2
a 2
改过之后:
row#0[8017] flag: ---D-, lock: 2
col 0; len 1; (1): 61
col 1; len 10; (10): 00 01 50 dd 21 80 07 99 00 00
row#1[7957] flag: -----, lock: 2
col 0; len 1; (1): 61
col 1; len 10; (10): 00 01 50 de 22 00 11 19 00 02
row#2[8002] flag: -----, lock: 0
col 0; len 1; (1): 62
col 1; len 10; (10): 00 01 50 dd 21 80 07 99 00 01
row#3[7987] flag: -----, lock: 0
col 0; len 1; (1): 63
col 1; len 10; (10): 00 01 50 de 22 00 11 19 00 00
row#4[7972] flag: -----, lock: 0
col 0; len 1; (1): 64
col 1; len 10; (10): 00 01 50 de 22 00 11 19 00 01
这里我们可以从trace文件中看到索引idx_testindex_pvalue中对于键值为'a'的global rowid已经由00 01 50 dd 21 80 07 99 00 00变成了00 01 50 de 22 00 11 19 00 02。
现在我们重建上述index,再来验证将上述index设为unusable的情况下索引idx_testindex_pvalue中对应于键值为'a'的global rowid是否会变?
SQL> update testindex set pkey=1 where pvalue='a';
1 row updated
SQL> commit;
Commit complete
SQL> select * from testindex;
PVALUE PKEY
------ ----------
b 1
a 1
c 2
d 2
SQL> drop index idx_testindex_pvalue;
Index dropped
SQL> create index idx_testindex_pvalue on testindex(pvalue);
Index created
未改之前:
row#0[8017] flag: -----, lock: 0
col 0; len 1; (1): 61
col 1; len 10; (10): 00 01 50 dd 21 80 07 99 00 02
row#1[8002] flag: -----, lock: 0
col 0; len 1; (1): 62
col 1; len 10; (10): 00 01 50 dd 21 80 07 99 00 01
row#2[7987] flag: -----, lock: 0
col 0; len 1; (1): 63
col 1; len 10; (10): 00 01 50 de 22 00 11 19 00 00
row#3[7972] flag: -----, lock: 0
col 0; len 1; (1): 64
col 1; len 10; (10): 00 01 50 de 22 00 11 19 00 01
SQL> alter index idx_testindex_pvalue unusable;
Index altered
SQL> update testindex set pkey=2 where pvalue='a';
update testindex set pkey=2 where pvalue='a'
ORA-01502: index 'DRAS.IDX_TESTINDEX_PVALUE' or partition of such index is in unusable state
SQL> ALTER SESSION SET SKIP_UNUSABLE_INDEXES = TRUE;
Session altered
SQL> update testindex set pkey=2 where pvalue='a';
1 row updated
SQL> commit;
Commit complete
SQL> select * from testindex;
PVALUE PKEY
------ ----------
b 1
c 2
d 2
a 2
改过之后:
row#0[8017] flag: -----, lock: 0
col 0; len 1; (1): 61
col 1; len 10; (10): 00 01 50 dd 21 80 07 99 00 02
row#1[8002] flag: -----, lock: 0
col 0; len 1; (1): 62
col 1; len 10; (10): 00 01 50 dd 21 80 07 99 00 01
row#2[7987] flag: -----, lock: 0
col 0; len 1; (1): 63
col 1; len 10; (10): 00 01 50 de 22 00 11 19 00 00
row#3[7972] flag: -----, lock: 0
col 0; len 1; (1): 64
col 1; len 10; (10): 00 01 50 de 22 00 11 19 00 01
可以从结果里看到,这时候当我将上述index设为unusable的情况下索引idx_testindex_pvalue中对应于键值为'a'的global rowid没有变!
这时候如果我们rebuild online的话是能修正上述错误的,因为rebuild online走的是全表扫描。但是如果我们只是rebuild,因为rebuild走的是index fast full scan,那这里oracle能正确的修正上述global rowid的错误吗?我们来验证一下:
SQL> alter index idx_testindex_pvalue rebuild;
Index altered
rebuild之后:
row#0[8017] flag: -----, lock: 0
col 0; len 1; (1): 61
col 1; len 10; (10): 00 01 50 de 22 00 11 19 00 03
row#1[8002] flag: -----, lock: 0
col 0; len 1; (1): 62
col 1; len 10; (10): 00 01 50 dd 21 80 07 99 00 01
row#2[7987] flag: -----, lock: 0
col 0; len 1; (1): 63
col 1; len 10; (10): 00 01 50 de 22 00 11 19 00 00
row#3[7972] flag: -----, lock: 0
col 0; len 1; (1): 64
col 1; len 10; (10): 00 01 50 de 22 00 11 19 00 01
从结果里我们可以看到,即便我这里用的是rebuild,oracle这里也已经将上述global rowid的错误修正。
为什么会这样?
很简单,因为在index是unusable的情况下,即使是直接rebuild,oracle这里也会走全表扫描。
SQL> select status from dba_indexes where index_name='IDX_TESTINDEX_PVALUE';
STATUS
--------
VALID
SQL> explain plan for alter index idx_testindex_pvalue rebuild;
Explained
SQL> select * from table(dbms_xplan.display);
PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost |
--------------------------------------------------------------------------------
| 0 | ALTER INDEX STATEMENT | | 9802 | 19604 | 13 |
| 1 | INDEX BUILD NON UNIQUE| IDX_TESTINDEX_PVALUE | | | |
| 2 | SORT CREATE INDEX | | 9802 | 19604 | |
| 3 | INDEX FAST FULL SCAN| IDX_TESTINDEX_PVALUE | 9802 | 19604 | |
--------------------------------------------------------------------------------
Note: cpu costing is off, PLAN_TABLE' is old version
11 rows selected
SQL> alter index idx_testindex_pvalue unusable;
Index altered
SQL> select status from dba_indexes where index_name='IDX_TESTINDEX_PVALUE';
STATUS
--------
UNUSABLE
SQL> explain plan for alter index idx_testindex_pvalue rebuild;
Explained
SQL> select * from table(dbms_xplan.display);
PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost |
--------------------------------------------------------------------------------
| 0 | ALTER INDEX STATEMENT | | 9802 | 19604 | 13 |
| 1 | INDEX BUILD NON UNIQUE| IDX_TESTINDEX_PVALUE | | | |
| 2 | SORT CREATE INDEX | | 9802 | 19604 | |
| 3 |
| 4 | TABLE ACCESS FULL | TESTINDEX | 9802 | 19604 | 13 |
--------------------------------------------------------------------------------
Note: cpu costing is off, PLAN_TABLE' is old version
12 rows selected
实验很有趣。
index unused 就说明index 数据可能是不正确的,rebuild,或者online 自然都要从表中重整index block 咯
另外explain for ddl 有可能不准确
谢谢提醒:)
这个反例是我特意构造出来的,只是想看一看oracle在索引有问题的情况下的表现。
rebuild index online也是走的全表扫描,而不是从索引扫描。
熊哥,我在文中提到“这时候如果我们rebuild online的话是能修正上述错误的,因为rebuild online走的是全表扫描”,咱们的观点是一致的呀。