ORACLE_CBO
========================
Oracle的聚簇因子对于查询IO的影响
Oracle中,对于同一个查询语句,有时候会很快的完成,有时候却很慢,但是表结构什么的完全一致,表中的数据也完全一致,这个具体是什么原因呢,就要从Index中的细节说起了。
在Oracle中的一个特殊的视图user_indexes中有一个特殊的列,名字是clustering_factor,这个值的内容就是如果访问表的整个表数据,会造成多少次数据库IO。我们可以通过下面的SQL语句来查看。
SELECT
A.INDEX_NAME,
B.NUM_ROWS,
B.BLOCKS,
A.CLUSTERING_FACTOR
FROM
USER_INDEXES A,
USER_TABLES B
WHERE
A.INDEX_NAME = ?
AND A.TABLE_NAME = B.TABLE_NAME
在这个SQL语句中,?代表的就是我们要检索的Index的名称。在表中数据有时候属于无序状态,这个时候的CLUSTERING_FACTOR比较接近NUM_ROWS,说明如果扫描整个表,每次都要根据Index来读取相应行的RowID,这个时候的IO操作很多,自然检索时间会比较长。如果数据有序的话,CLUSTERING_FACTOR比较接近BLOCKS,说明相邻的数据在一个块中,减少了IO操作数量,自然检索时间会大大降低。
下面这一段是Oracle 手册中关于CLUSTERING_FACTOR的说明:
If the value is near the number of blocks, then the table is very well ordered. In this case, the index entries in a single leaf block tend to point to rows in the same data blocks.
If the value is near the number of rows, then the table is very randomly ordered. In this case, it is unlikely that index entries in the same leaf block point to rows in the same data blocks.
========================
Cost = (
#SRds * sreadtim +
#MRds * mreadtim +
#CPUCycles / cpuspeed
) / sreadtim
对其中因子的解释是:
#SRDS:单数据块读的次数;
#MRDS:多数据块读的次数;
SREADTIM:一次单数据块读的时间;
MREADTIM:一次多数据块读的时间;
#CPUCYCLES:完成查询所需要发出的CPU指令数
CPUSPEED:CPU的处理速度
#SRDS = BLEVEL + INDLEAFBLKS*INDSEL + TABSEL*CLUF (索引扫描)
#MRDS = TABBLKS/MBRC (全表扫描、快速索引全扫描)
SREADTIM = IOSEEKTIM + BLKSIZ/IOTFRSPEED
MREADTIM = IOSEEKTIM + MBRC * BLKSIZ/IOTFRSPEED
其中,
BLEVEL:索引高度;
INDLEAFBLKS:索引叶子数据块数;
INDSEL:索引选择性;
TABSEL:表选择性;
TABBLKS:表在HWM下的数据块数;
MBRC:多数据块读的一次读取的数据块数,Multi_Block_Read_Count;
BLKSIZ:数据块大小;
IOSEEKTIM:IO寻址时间,System Statistics中给出,默认为10ms;
IOTFRSPEED:IO传输速度,System Statistics中给出,默认为4096字节/ms。
表部分
#Rows:表的记录数;
#Blks:表的HWM以下的数据块数;
AvgRowLen:表记录的平均长度
索引部分
Col#:索引中字段在表中的位置;
LVLS:索引高度,即BLevel;
#LB:索引叶子节点数据块数;
LB/K:平均每个键值的叶子节点数据块数;
DB/K:平均每个键值的表数据块数;
CLUF:聚簇因子(Clustering Factor)
字段部分
(#n):字段位置;
A(VARCHAR2):字段名称和数据类型;
AvgLen:字段平均长度;
NDV:字段中唯一值数量;
Nulls:字段中空值数量;
Density:字段密度
规则1:CPUSPEED与#CPUCYCLES无关
规则2:IOTFRSPEED与#CPUCYCLES无关
规则3:IOSEEKTIM与#CPUCYCLES无关。
公式22:COST_CPU = TYPFAC*TABROWS + 0.32*TABBLKS*TABSIZ + 4500*TABBLKS
其中
TYPFAC = ROUND((130 + MAXFLTCOLPOS*20 + EXPTYPEFAC1+ EXPTYPEFAC2* EXPSEL1 + 20*EFFQRYCOLNUM*MAX(1,ROUND(EXPTYPEFAC *TABROWS,0))/TABROWS)*TABROWS,0)/TABROWS
其中,子句的计算是由它的上优先级的子句计算得出,计算式如下:
AND子句:
EXPTYPEFAC = MIN((SUBEXPTYPFAC1+ SUBEXPTYPFAC2*SUBEXPSEL1), (SUBEXPTYPFAC2+ SUBEXPTYPFAC1*SUBEXPSEL2)
EXPSEL = SUBEXPSEL1*SUBEXPSEL2
OR子句:
EXPTYPEFAC = MIN((SUBEXPTYPFAC1+ SUBEXPTYPFAC2*(1-SUBEXPSEL1)), (SUBEXPTYPFAC2+ SUBEXPTYPFAC1*(1-SUBEXPSEL2))
EXPSEL = SUBEXPSEL1 + SUBEXPSEL2 - SUBEXPSEL1*SUBEXPSEL2
其中SUBEXPTYPFAC和SUBEXPSEL可以为子句或者字段的TYPFAC和SELECTIVITY。
不同数据类型字段的TYPFAC:
数据类型
COLTYPEFAC
CHAR、VARCHAR2
50
NUMBER
150
DATE
300
当匹配符为LIKE时,COLTYPEFAC_NEW = COLTYPEFAC + 50
当匹配符为IN、NOT IN时COLTYPFAC_NEW = COLTYPEFAC*(1-1/NDV)^0+COLTYPEFAC*(1-1/NDV)^1+…+COLTYPEFAC*(1-1/NDV)^(INNUM-1)
各种匹配符的选择性计算如下:
匹配符
COLSEL
>、=
1/20
LIKE
1/20
=
1/NDV
<>
1-1/NDV
IN
NOTINNUM*1/NDV
NOT IN
(1-1/NDV)^NOTINNUM
当作用NOT时,选择性变为 (1-原选择性).
[@more@]