[Oracle] oracle统计信息
Oracle统计信息
Oracle数据库里的统计信息可以分为6种类型:
- 表的统计信息
- 索引的统计信息
- 列的统计信息
- 系统统计信息
- 数据字典统计信息
- 内部对象统计信息
图 1: Oracle统计信息
基于CBO成本计算的几个重要概念:
-
Cardinality (集的势)
-
含义:
Cardinality可以理解为SQL扫描后所得到的集合
-
计算公式:
Cardinality=MAX(Cardinality Factor * Rowcount, 1)
-
Cardinality Factor计算
-
"="查询
Cardinality Factor = 1/NUM_DISTINCT
-
">", "<", ">=", "<="查询
Cardinality Factor = (1/NUM_DISTINCT) + (1/NUM_ROWS)
-
in查询
Cardinality Factor = in_count/NUM_DISTINCT
-
"<>"查询
Cardinality Factor = (1 - (1/NUM_DISTINCT))
-
not in查询
Cardinality Factor = (1 - (1/NUM_DISTINCT)) ^ (not_in_count)
-
-
-
Selectivity (选择度)
-
含义:
Selectivity可以理解为SQL中谓词过滤结果集和报错表记录数之间的比例 -😃
从选择度的强弱来看, 接近1表示弱选择性, 几乎full table scan; 然而接近0表示强选择性, 既通过index过滤后可以得到目标结果集.
图 2: Selectivity强弱
图 3: Selectvity scan
-
Selectivity实例
-
没有null值的等值查询Selectivity计算公式:
selectivity_without_null = (1/NUM_DISTINCT)
-
有null值的等值查询Selectivity计算公式:
selectivity_with_null = (1/NUM_DISTINCT) * (NUM_ROWS-NUM_NULLS)/NUM_ROWS
-
">"查询, 且处于LOW_VALUE和HIGH_VALUE之间
selectivity = ((HIGH_VALUE-VAL) / (HIGH_VALUE-LOW_VALUE)) * Null_Adjust
Null_Adjust = (NUM_ROWS - NUM_NULLS) / NUM_ROWS -
"<"查询, 且处于LOW_VALUE和HIGH_VALUE之间
selectivity = ((VAL-LOW_VALUE) / (HIGH_VALUE-LOW_VALUE)) * Null_Adjust
Null_Adjust = (NUM_ROWS - NUM_NULLS) / NUM_ROWS -
">="查询, 且处于LOW_VALUE和HIGH_VALUE之间
selectivity = ((HIGH_VALUE-VAL) / (HIGH_VALUE-LOW_VALUE) + 1/NUM_DISTINCT) * Null_Adjust
Null_Adjust = (NUM_ROWS - NUM_NULLS) / NUM_ROWS -
">="查询, 且处于LOW_VALUE和HIGH_VALUE之间
selectivity = ((VAL-LOW_VALUE) / (HIGH_VALUE-LOW_VALUE) + 1/NUM_DISTINCT) * Null_Adjust
Null_Adjust = (NUM_ROWS - NUM_NULLS) / NUM_ROWS -
">,<"查询, 且处于LOW_VALUE和HIGH_VALUE之间
selectivity = ((VAL2-VAL1)/(HIGH_VALUE-LOW_VALUE) + 2/NUM_DISTINCT) * Null_Adjust
Null_Adjust = (NUM_ROWS - NUM_NULLS) / NUM_ROWS
-
-
-
Clustering factor (聚簇因子)
-
含义:
按照索引建值排序的索引行和存储于对应表中数据行的存储顺序的相似程度;
-
算法:
-
Clustering factor初始值为1
-
从index最左边的叶子块开始
-
最左边叶子块的第一个索引健值所在的索引行开始顺序扫描, 在顺序扫描的过程中, 比对当前索引行的rowid和它之前的那个索引行的rowid, 如果这两个rowid并不是指向同一个表块, 那么聚簇因子++; 如果这两个rowid指向同一个表块, 那么不改变聚簇因子当前值
-
持续3步骤, 直到顺序扫描完目标索引所有叶子块里的所有索引行
聚簇因子高的索引走index range scan时比相同条件下聚簇因子低的的索引要耗费更多的物理IO, 所以聚簇因子高的索引走index range scan的成本会比相同条件下聚簇因子低的索引走index range scan的成本高.
-
-
算法实例
图 2: 聚簇因子计算实例
这是一个比较极端的例子, 在index的没有任何相邻索引行记录的rowid中指向表中相同的数据块, 按照上面的算法可以得到聚簇因子是20;
降低目标index的聚簇因子唯一方法就是对表中数据按照目标index的索引健值排序后重新存储.
CBO在做index range scan时的成本计算公式:
IRS_Cost = I/O Cost + CPU Cost I/O Cost = Index Access I/O Cost + Table Access I/O Cost Index Access I/O Cost = BLEVEL + CELL(#LEAF_BLOCKS * IX_SEL) Table Access I/O Cost = CEIL(CLUSTERING_FACTOR * IX_SEL_WITH_FILTERS)
可以看出成本几乎和聚簇因子成正比.
-
依稀记得那时2013年, 那会我还在某鹅厂做Game DBA的工作, 当时负责的游戏中有两款是Oracle Database的(都是棒子开发的, CF和AVA), 有一次业务发布后发现AVA DB机器IO负载过大的问题, 深入去分析和定位最后发现是index效果不太好, 导致Physical Read和Logical Read很高, 从而造成IO压力 -_-
大致的方法就是:
CPU/IO ? -> AWR -> Segments by Physical Reads ? -> Object Name(SQL) ->
Trace/Explain -> Physical Read/Logical Read/A-Rows/E-Rows -> Adjust Idex(Data distrubitu)
详细可以参考 <某游戏大区DB IO负载过高分析>