关于索引的创建方式:create online、create offline、rebuild online、rebuild offline四种,而这四种在性能方面是否有值得摸索的地方了,小鱼个人觉得还是有必要的。 先来看看create online和create offline创建索引的两种方式: SQL select * from v$vers

关于索引的创建方式:create online、create offline、rebuild online、rebuild offline四种,而这四种在性能方面是否有值得摸索的地方了,小鱼个人觉得还是有必要的。

先来看看create online和create offline创建索引的两种方式:

SQL> select * from v$version where rownum<2;

BANNER

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

Oracle Database 10g Enterprise Edition Release 10.2.0.4.0 - 64bi

SQL> create table t as select * from dba_objects;

Table created.

SQL> oradebug event 10053 trace name context forever,level 1;

Statement processed.

SQL> create index ind_id on t(object_id);

Index created.

SQL> drop index ind_id;

Index dropped.

SQL> create index ind_id on t(object_id) online;

Index created.

SQL> oradebug event 10053 trace name context off;

Statement processed.

SQL> oradebug tracefile_name;

g:\oracle\product\10.2.0\admin\ora10g\udump\ora10g_ora_8328.trc

看看event 10053 trace file

1) 直接offline创建索引

Current SQL statement for this session:

create index ind_id on t(object_id)

SYSTEM STATISTICS INFORMATION

*****************************

Using NOWORKLOAD Stats

CPUSPEED: 1220 millions instruction/sec

IOTFRSPEED: 4096 bytes per millisecond (default is 4096)

IOSEEKTIM: 10 milliseconds (default is 10)

***************************************

BASE STATISTICAL INFORMATION

***********************

Table Stats::

Table: T Alias: T

#Rows: 50217 #Blks: 689 AvgRowLen: 93.00

SINGLE TABLE ACCESS PATH

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

BEGIN Single Table Cardinality Estimation

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

Table: T Alias: T

Card: Original: 50217 Rounded: 50217 Computed: 50217.00 Non Adjusted: 50217.00

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

END Single Table Cardinality Estimation

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

Access Path: TableScan

Cost: 153.06 Resp: 153.06 Degree: 0

Cost_io: 152.00 Cost_cpu: 15452242

Resp_io: 152.00 Resp_cpu: 15452242

Best:: AccessPath: TableScan

Cost: 153.06 Degree: 1 Resp: 153.06 Card: 50217.00 Bytes: 0

Final - All Rows Plan: Best join order: 1

Cost: 177.0789 Degree: 1 Card: 50217.0000 Bytes: 251085

Resc: 177.0789 Resc_io: 176.0000 Resc_cpu: 15794071

Resp: 177.0789 Resp_io: 176.0000 Resc_cpu: 15794071

Plan Table

============

------------------------------------------+-----------------------------------+

| Id | Operation | Name | Rows | Bytes | Cost | Time |

------------------------------------------+-----------------------------------+

| 0 | CREATE INDEX STATEMENT | | | | 177 | |

| 1 | INDEX BUILD NON UNIQUE | IND_ID | | | | |

| 2 | SORT CREATE INDEX | | 49K | 245K | | |

| 3 | TABLE ACCESS FULL | T | 49K | 245K | 153 | 00:00:02 |

------------------------------------------+-----------------------------------+

2) Online创建索引:

Current SQL statement for this session:

create index ind_id on t(object_id) online

--相同部分内容不重复列出

SINGLE TABLE ACCESS PATH

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

BEGIN Single Table Cardinality Estimation

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

Table: T Alias: T

Card: Original: 50217 Rounded: 50217 Computed: 50217.00 Non Adjusted: 50217.00

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

END Single Table Cardinality Estimation

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

Access Path: TableScan

Cost: 153.06 Resp: 153.06 Degree: 0

Cost_io: 152.00 Cost_cpu: 15452242

Resp_io: 152.00 Resp_cpu: 15452242

Best:: AccessPath: TableScan

Cost: 153.06 Degree: 1 Resp: 153.06 Card: 50217.00 Bytes: 0

*********************************

Final - All Rows Plan: Best join order: 1

Cost: 153.0555 Degree: 1 Card: 50217.0000 Bytes: 251085

Resc: 153.0555 Resc_io: 152.0000 Resc_cpu: 15452242

Resp: 153.0555 Resp_io: 152.0000 Resc_cpu: 15452242

Plan Table

============

------------------------------------------+-----------------------------------+

| Id | Operation | Name | Rows | Bytes | Cost | Time |

------------------------------------------+-----------------------------------+

| 0 | CREATE INDEX STATEMENT | | | | 153 | |

| 1 | INDEX BUILD NON UNIQUE | IND_ID | | | | |

| 2 | SORT CREATE INDEX | | 49K | 245K | | |

| 3 | TABLE ACCESS FULL | T | 49K | 245K | 153 | 00:00:02 |

------------------------------------------+-----------------------------------+

这个在创建方式上都是去通过表扫描来创建索引,这个应该是很好理解的,因为此时没有索引,只能通过表扫描然后排序创建索引。

SQL> oradebug setmypid

Statement processed.

SQL> oradebug event 10053 trace name context forever,level 12;

Statement processed.

SQL> alter index ind_id rebuild;

Index altered.

SQL> alter index ind_id rebuild online;

Index altered.

SQL> oradebug event 10053 trace name context off;

Statement processed.

SQL> oradebug tracefile_name;

g:\oracle\product\10.2.0\admin\ora10g\udump\ora10g_ora_9960.trc

3) Offline rebuild index的trace信息

SINGLE TABLE ACCESS PATH

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

BEGIN Single Table Cardinality Estimation

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

Table: T Alias: T

Card: Original: 50217 Rounded: 50217 Computed: 50217.00 Non Adjusted: 50217.00

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

END Single Table Cardinality Estimation

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

Access Path: TableScan

Cost: 153.06 Resp: 153.06 Degree: 0

Cost_io: 152.00 Cost_cpu: 15452242

Resp_io: 152.00 Resp_cpu: 15452242

Best:: AccessPath: TableScan

Cost: 153.06 Degree: 1 Resp: 153.06 Card: 50217.00 Bytes: 0

Plan Table

============

------------------------------------------+-----------------------------------+

| Id | Operation | Name | Rows | Bytes | Cost | Time |

------------------------------------------+-----------------------------------+

| 0 | CREATE INDEX STATEMENT | | | | 153 | |

| 1 | INDEX BUILD NON UNIQUE | IND_ID | | | | |

| 2 | SORT CREATE INDEX | | 49K | 245K | | |

| 3 | INDEX FAST FULL SCAN | IND_ID | | | | |

------------------------------------------+-----------------------------------+

4) Online rebuild 的trace信息

SINGLE TABLE ACCESS PATH

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

BEGIN Single Table Cardinality Estimation

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

Table: T Alias: T

Card: Original: 50217 Rounded: 50217 Computed: 50217.00 Non Adjusted: 50217.00

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

END Single Table Cardinality Estimation

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

Access Path: TableScan

Cost: 153.06 Resp: 153.06 Degree: 0

Cost_io: 152.00 Cost_cpu: 15452242

Resp_io: 152.00 Resp_cpu: 15452242

Best:: AccessPath: TableScan

Cost: 153.06 Degree: 1 Resp: 153.06 Card: 50217.00 Bytes: 0

Current SQL statement for this session:

create index ind_id on t(object_id) online

Plan Table

============

------------------------------------------+-----------------------------------+

| Id | Operation | Name | Rows | Bytes | Cost | Time |

------------------------------------------+-----------------------------------+

| 0 | CREATE INDEX STATEMENT | | | | 153 | |

| 1 | INDEX BUILD NON UNIQUE | IND_ID | | | | |

| 2 | SORT CREATE INDEX | | 49K | 245K | | |

| 3 | TABLE ACCESS FULL | T | 49K | 245K | 153 | 00:00:02 |

------------------------------------------+-----------------------------------+

这里看出执行计划是存在差异的,offline rebuild index是通过现有的索引fts、排序来创建索引,而online rebuild index则是通过现有的表fts、sort排序来创建索引,可以看出两种rebuild方式的对象是不一样的,而且细心的话我们发觉10053 offline rebuild index的trace中,cbo分析的可选择的执行计划中没有index ffs的方式,只有tablescan的方式,但是执行计划下面却是列出了index fast full scan,这个确实小鱼也找过一些资料,没有发觉合理的解释。

看看rebuild online时oracle具体是如何实现在线dml的

PARSING IN CURSOR #2 len=33 dep=0 uid=0 oct=9 lid=0 tim=29773760836 hv=1974521930 ad='5d5072c8'

alter index ind_id rebuild online

END OF STMT

PARSE #2:c=156001,e=314135,p=13,cr=342,cu=0,mis=1,r=0,dep=0,og=1,tim=29773760831

BINDS #2:

=====================

PARSING IN CURSOR #5 len=41 dep=2 uid=0 oct=3 lid=0 tim=29773761671 hv=1572239410 ad='5da531a8'

select ts#,online$ from ts$ where name=:1

END OF STMT

PARSE #5:c=0,e=184,p=0,cr=0,cu=0,mis=1,r=0,dep=2,og=4,tim=29773761667

BINDS #5:

kkscoacd

Bind#0

oacdty=01 mxl=32(06) mxlc=00 mal=00 scl=00 pre=00

oacflg=20 fl2=0000 frm=01 csi=852 siz=32 off=0

kxsbbbfp=0c009d28 bln=32 avl=06 flg=05

value="SYSTEM"

EXEC #5:c=0,e=842,p=0,cr=0,cu=0,mis=1,r=0,dep=2,og=4,tim=29773762622

FETCH #5:c=0,e=25,p=0,cr=2,cu=0,mis=0,r=1,dep=2,og=4,tim=29773762677

=====================

PARSING IN CURSOR #3 len=158 dep=1 uid=0 oct=1 lid=0 tim=29773762842 hv=722598008 ad='5d506d28'

create table "SYS"."SYS_JOURNAL_56527" (C0 NUMBER, opcode char(1), partno number, rid rowid, primary key( C0 , rid )) organization index TABLESPACE "SYSTEM"

END OF STMT

PARSE #3:c=0,e=1689,p=0,cr=2,cu=0,mis=1,r=0,dep=1,og=4,tim=29773762838

BINDS #3:

这个"SYS"."SYS_JOURNAL_56527"是一个类似的日志表,记录online rebuild期间数据的改变,当索引创建完毕后,会把新的记录通过这个表更新到新的索引中,也正是因为这个日志表保证了在online rebuild index时不影响dml操作,在创建完毕后oracle会把这个日志表记录更新到索引时候会对表加锁,此时也会短暂的阻止表dml操作。

上面简单的分析了online rebuild和offline rebuild创建索引的两种方式,其中offline rebuild是直接根据现有的索引来创建的,创建方式是index fast full scan然后sort index create,而online index是单独根据现有的表段来table access scan然后sort index create,并在此期间创建一个类似的SYS_JOURNAL_56527日志表来记录创建期间表的dml操作记录,在创建完毕后将日志表的记录更新到新的索引中,并删除原来的旧的索引。

一般而言offline rebuild的方式要比online rebuild快一些,由于可以直接利用旧的索引来重建,而且索引一般是比表小的,index fast full scan相比也要比table access scan扫描成本低一些,而online rebuild最吸引用户的地方就是不影响在线的dml了。

文章中对于offline rebuild index中的10053 trace的实际的执行计划和cbo可选择执行计划确实是存在出入的,这个疑点大家有理解的也欢迎解惑,小鱼个人觉得是可选择执行计划中出现了问题,改天有兴趣换到oracle 11g中来看看是否修正了这个问题。