1.什么是统计信息 2.统计信息的基本内容 统计信息包含几个重要的宏观数据:
如果做了列级或者索引的收集,那么统计信息还包括下列信息:
CBO依据这些信息对选择率和基数进行估算。 3.直方图
基本的统计信息并不能完全反应数据的分布情况,考虑下面这个例子,假定字段AGE, 表示年龄, 给出最小年龄10, 最大年龄80, 总的人数为10万,优化器还是不知道这些人的年龄分布情况。一个合理的假定是所有的记录都是平均分布的,但是现实世界并不完全这样,因此需要更加详细的信息,因此引入了直方图这个概念。直方图又分为频率直方图和等高直方图。 频率直方图有些字段的取值范围非常有限,比如人类的年龄,一般不可能超过120, 因此无论表中有多少记录,年龄字段的唯一值个数都不会超过120, 我们可以采样部分记录,统计出每个年龄(0-120)的记录数,可以使用120个(V, count)二元组作为元素的数组,来表示这个频率直方图。比如这个表有1亿条记录,随机采用5%的记录,记录每个年龄出现的次数,然后再乘以20,即可获得这个年龄字段每一个取值的记录数目。 等高直方图频率直方图虽然精确,但是它只能处理取值范围较小的情况,如果字段的取值范围很大,那么就不可能为每一个值统计出它的出现次数,这个时候我们需要等高直方图。等高直方图是针对一个数据集合不同值个数很多的情况,把数据集合划分为若干个记录数相同或相近的不同区间,并记录区间的不同值个数。每个区间的记录数比较接近,这就是所谓等高的含义。 系统也适用一个数组来表示等高直方图,数组的每一项包含下列信息:
目前等高直方图数组的项(或者称为桶)的个数为131个,而频率直方图的个数为2000。等高直方图的目的,是尽可能精确地描述不同值数据的分布情况。在数据取值密集的地方那个,用来描述的桶就多,反之则少。利用它,可以比较精确地估算一个特定范围内记录的数量。 4.统计信息的收集
DM7收集统计信息有两种方法,一是通过一些存储过程来收集,二是用DBMS_STATS包来收集。 --对表上所有的索引生成统计信息 SP_TAB_INDEX_STAT_INIT --对库上所有模式下的所有用户表上的所有索引生成统计信息 SP_DB_STAT_INIT --对指定的索引生成统计信息 SP_INDEX_STAT_INIT --对指定的列生成统计信息,不支持大字段列 SP_COL_STAT_INIT ----------详见《DM SQL语言手册附录3》 这里推荐使用DBMS_STATS包来收集,有别于存储过程,通过这个工具包收集可以指定采用率, 在数据分布极不均匀的情况下,提高统计信息的采用率,有助于提供更精确的统计信息。 使用DBMS_STATS首先得调用一个系统存储过程来创建这个包: SP_CREATE_SYSTEM_PACKAGES(1); 包里面常用的存储过程有:
根据模式名,表名和列名获得该列的统计信息。
根据模式名,索引名获得该索引的统计信息。
根据设定的参数,收集表的统计信息。
根据设定的参数,收集索引的统计信息
收集模式下对象的统计信息 --具体用法见《DM SQL语言手册》第二十章 举例说明: --收集SYSDBA模式下对象的统计,采样率为50%,
对该模式下所有的列做统计信息,大字段的列除外 5.统计信息的查看 --解读统计信息 --1.类型:频率直方图 --2.ENDPOINT_VALUE样本值: 1 --3.ENDPOINT_HEIGHT 样本值的个数:773 select COUNT(*) from TEST_TJ where age=1 6.统计信息对查询的影响 --删除表上的统计信息 DBMS_STATS.DELETE_TABLE_STATS('SYSDBA', 'TEST_TJ'); --在没有统计信息的情况下,查看一下下列SQL的执行计划 explain select count(*) from TEST_TJ where age = 20; 1 #NSET2: [11, 1, 4] 2 #PRJT2: [11, 1, 4]; exp_num(1), is_atom(FALSE) 3 #AAGR2: [11, 1, 4]; grp_num(0), sfun_num(1) 4 #SLCT2: [11, 2500, 4]; TEST_TJ.AGE = 20 5 #CSCN2: [11, 100000, 4]; INDEX33559695(TEST_TJ) --以age为条件字段,进行等值扫描,计划评估出来的行数是2500 这个2500是怎么来的呢? select * from "V$DM_INI" where "PARA_NAME" like 'SEL%';
如果没有统计信息可用,则对于 列名= <常量>的谓词,选择率固定为SEL_RATE_EQU, 缺省为2.5%,其他谓词一律为SEL_RATE_SINGLE, 缺省为5%。 那么在这个例子中这个2500=100000*0.025; 我们再来看下面这个SQL的计划: explain select count(*) from TEST_TJ where age > 20; 1 #NSET2: [11, 1, 4] 2 #PRJT2: [11, 1, 4]; exp_num(1), is_atom(FALSE) 3 #AAGR2: [11, 1, 4]; grp_num(0), sfun_num(1) 4 #SLCT2: [11, 5000, 4]; TEST_TJ.AGE = 20 5 #CSCN2: [11, 100000, 4]; INDEX33559695(TEST_TJ) 这里的5000=100000*0.05; 很显然这个默认值代价的估算是不准确的,特别是对于复杂的查询,如果没有统计信息CBO很有可能选择错误的执行计划,我们收集一下这个表的统计信息,再来对比一下执行计划: DBMS_STATS.GATHER_TABLE_STATS('SYSDBA', 'TEST_TJ',null,100,false,'FOR ALL COLUMNS SIZE AUTO'); |