统计信息的重要性
很显然,在这个案例中,引起
SQL执行效率低下的主要原因在于,表中的一些关键列的统计信息丢失。也就是说,是没有准确的统计信息导致了性能问题。
在
oracle
数据库发展到
11g的今天,让我们忘记基于规则(Rule)的优化吧。自oracle 7开始使用cbo以来一直到最新的oracle11g,基于成本的优化器已经越来越智能和稳定。经过笔者的测试,10gR2与9iR2这两个日前大量使用的版本相比较,CBO的变化比较大.比如在Cost和选择率的计算上有许多的变化,新增的连接方式,等等。而11g相对于10gR2来说,变化就非常小了。这反映出CBO已经比较稳定,改进的余地越来越少。而网上有一些消息,称正在研发中的oracle12g在cbo优化器方面有着非常巨大的变化,让我们拭目以待。
那是不是可以说到了今天oracle在优化方面已经没有什么改进了呢?答案是否定的。从8i一直到11g,oracle对于性能方面,除了CBO优化器(CBO Optimizer)本身之外,还包括下而一些重要的改进和提高:
从oracle
10g开始出现的SQL Tuning advisor,能够帮助DBA自动进行sQL优化。大大减少以往完全依赖于人工进行优化的工作量。提升了优化工作效率。
oracle 9i及之前版本的Stored outline。Oracle10g的SQL Profile。一直演进到11g的SQL Plan Management。在解决SQL执行计划稳定性方面,Oracle一直在不断地提高。
从最早的analyze命令到现在复杂的,功能强大dbms_stats包。Oracle数据库的每一个发行版本都在统计信息的1文集方而进行大的改进和完善.
Oracle的执行引擎采用新的算法和
技术。比如ORACLE10g开始使用的HASH GROUP BY等,提高SQL的执行效率。
Oracie11g开发的新技术,Result cache.通过结合缓存大大提高频繁查询的小数据集的SQC执行速度。
还有很多不同程度的,甚至于我们不能直接观察到的改进。不再一一列举。
但是,对于一个oracle数据库来说,在系统的逻辑和物理结构既定的情况下,优化统计信息的完整和准确与否,是决定着数据库能否高效运行的关键。oracle中的统计信息是SQL语句能够最优化运行的基础。从最早的analyze命令到dbms_stats包,oracle数据库的每一个发行版本都在统计信息的收集方面进行改进和完善。
统计信息的相关知识
优化器使用的统计信息,主要包括两类,其一死系统统计信息(System Statistics),用于反映系统中CPU的处理速度,以及从磁盘上读取数据块的速度;另一类就是表和索引的统计信息。本节将重点讨论表和索引的统计信息,只是简单地提及系统统计信息,对于系统统计信息来说,如果从9i升级到10g,或者数据库从一台主机迁移到另一台主机,则由于系统统计信息对CPU成本和多块读成本的计算有作常大的影响,所以可能会导致SQL的执行计划发生变化。当然变化有正面的。也可能会产生负面影响即引起性能降低,这样的情况需要引起注意;
面临的问题与挑战
一个复杂的、大容量、高并发、高可用的业务系统,比如像电信、金融等行业中的核心系统,其ORACLE数据库DBA常常面临下面的问题和挑战:
·平时运行正常的系统,也没有什么改动,为什么某一天突然就变慢了?
·完全相同的一个SQL,在
RAC数据库中的一个节点上运行正常,为什么在另一个节点上就非常慢。
·在使用绑定变量和数据倾斜(Skew)引起的性能低下之间如何抉择?
·系统的维护时间窗口越来越短,而数据量也越来越大,收集统计数据该采取什么样的策略?
·对于数据量非常大的,每犬又会产生大量数据的分区表,该如何收集统计信息?
·针对这些问题和挑战,我们该如何应对?
这些问题,归结起来,就是我们如何为oracle数据库制定一套行之有效的统计信息收集策略。其实并没有一个简单的答案。也就是说,没有普遍适用的'银弹’。oracle一直在改进DBMS_STAT包,就从侧面反映出ORACLE在统计信息收集功能方面还不够完善,不能解决目前面临的很多与统计信息相关的问题。
虽然如此,我们还是应该为ORACLE数据库制定一套策略,来更好地收集统计信息,保障数据库平稳高效地运行。下面是笔者的一些建议:
1.对于一个Oracle数据库,如果我们一查不去更新表和索引的统计信息,那么随着时间的推移和数据量的增长,系统在某一天突然变慢,这将是必然会出现的状况。因此必须制定一个策略,来及时收集数据库中表和索引的统计信息。
2.如果系统是在上线初期甲或者系统已经运行很久,但还没有有效的策略来收集统计信息,这个时候,我们制定一个初始策略。利用DBMS_STAT进行统计数据收集时,使用自动的选项。oracle lOg及1lg已经是采用了自动的选项进行收集。而对于9来说,我们用DBMS_STATS中GATHER_DATABASE_STATS、GATHER_SCEEMA_STAT、GATHER_TABLE_STATS等过程收集统计信息时。对ESTIMATE_PERCENT参数使用AUTO_SAMPLE_SIZE,METHOD_OPT参数使用“FOR ALL COLUMNS SIZE AUTO“,OPTIONS参数使用”GATHER AUTO“等。值得注意的是,不管是AUTO,还是SKEWONLY选项收集列上的统计信息,Oracle都可能会收集到错误的数据。比如为不应该收集直方图的列收集了直方图,而应该收集直方图的列却没有收集,或者直方图的bucket数量不合适。这个问题在oracle的低版本如9i中比较突出,在11g中也没有多大的改善。如果系统中数据倾斜的列不多,也就是需要收集直方图的列不多,建议将METHOD_OPT参数设置为“FOR ALL COLUMNS SIZE1”。对于需要收集直方图的列,单独进行收集。
3.按自动方式收集完统计信息之后。检查表和索引(至少包括主要的业务表及索引)的统计数据是否能够准确地反映数据分布。不过应注意,我们不要期望统计信息能“完美”地反映数据分布,只要能够相对准确地反映数据分布即可。比如,一张有100万行数据的表,某一列有100万个不同的值,如果统计信息中该列有50万个不同的值,对优化器来说,差别并不是很大。但是如果只有10万甚至5万个不同的值,差别就非常大了,可能会导致优化器选择不够优化的执行计划。
如果统计信息不准确的表和索引太多,则表明自动选项的收集策略不合适,需要调整参数,比如很多列错误地收集了直方图,尝试将METHOD_OPT参数设置为“FOR ALL COLUMNS SIZE SKEWONLY“直到能够保证大部分表和索引是准确的。如果到最后自动收集方式完全不合适,则需要考虑完全定制的收集策略,那样的策略比较复杂,维护难度比较大。
对于少数的统计信息不准确的表和索引,如有可能我们将这些表排除在自动收集策略之外,10g及以上版本,用LOCK_TABLE_STATS过程锁定表及其索引的统计信息,避免自动收集策略收集这些表和索引的统计信息。然后使用单独的过程来收集表和索引的统计信息,比如指定不同的采样比例,为METHOD_OPT参数指定不同的值等。
4.在使用绑定变量和数据倾斜的列之间。寻找一个折衷的方案。由于绑定变量窥探(Bind Peeking)可能会导致一个SQL选择了错误的执行计划,甚至出现同一个SQL在RAC中不同节点选择不同的执行计划的情况。对于那样的列,应评估绑定变量与使用直方图,哪一个选择有更大的收益。如果在这个列上有连接或比较的SQL执行得非常频繁,那么应考虑使用绑定变量,不在那个列上收集直方图;反之,如果收集了直方图之后,与此相关的SQL引起了严重的性能问题,导致数据库整体性能大幅下降.或者严重影响应用的响应时间和吞叶量,应考虑修改应用,在那个列上不使用绑定变量。这个问题在llg已经得到了比较好的解决,那就是11g的新特性-自适应游标共享〔adaptive Cursor Sharing },详细情况可参阅oracle的在线文档。
5.对于数据量非常大并且更新非常频繁的表,按天收集统计信息仍然显得不够。在有些系统中,就算是按大划分的RANGE分区,数据的增长也非常快,可以在短时间内从0条增长到数百万行甚至上干万行。并且对于这样的表,数据变化最大的分区即当天所在的分区,往往也用得最多。对于这样的分区,频繁进行统计信息的收集,代价又非常高,一个可行的办法是使用DBMS_STATS.SET_TABLE_STATS、DBMS_STATS.SET_COLUMNS_STATS等过程手工设置统计信息,但前提是需要对表的数据分布有比较清楚的了解。也要注意在一些特定的时候,数据量的变化会跟平时不太一样,比如节假日等。
笔者曾见过这样一个系统,该系统中很多按大分区的表,不幸的是,在侮天凌晨进行统计信息收集时。当天的分区只有数万甚至只有数千行数据.结果在白天时,当天的分区数据增长很多,很多访问那个分区的SQL执行效率非常差、对于这样的表,就应该进行特别处理,不能依赖于基本的统计信息收集策略。如果一个表特别大,而系统的维护窗口又非常小,要进行统计信息的收集,并没有想像中那么复杂:首先,如果数据变化没有积累到一定的量(比如超过10%)那么可以不进行收集。其次.收集统计信息时,较小的采样比例一般就能满足要求。注意,我们的目标是让优化器使用正确的执行计划,而不是统计信息本身。
不同业务对应的表和索引的统计信息。比如3天一个周期收集统计信息,第1天收集业务A的表和索引,第2天收集业务B的表和索引,如此等等。
6.而一些特殊的表,比如临时表、一些数据处理
过程中产生的中间表、有关联列的表,则采用定制的
方法,比如使用SET_TABLE_STATS等过程。如果仍然不能满足要求,则考虑在SQL中使用动态抽样(Dynamic Sampling)或使用Store outline、SQL Profile等手段。
7.统计信息的收集,本身可以说是系统优化中的重要一环。可以说,优化工作是一个长期的,循环反复的过程,而统计信息的收集策略,也是一个逐渐完善的过程。对于系统运行中发现的由于统计信息问题导致性能低下的间题甲要及时修Gj完善收集策略。
总之,统计信息的收集策略,包括两个部分:一个自动化的基本策略,收集大部分的统计信息;再使用定制的手段,去处理前者不能解决的问题。当然,定制的过程仍然可以封闭在过程中,进行自动化地处理。
关于收集统计信息的策略和指南,可参考Metalink文档44961.1。
BTW:顺便提一下直方图的一些限制:
o all predicates on the column use bind variables
o the column
data is uniformly distributed
o the column is not used in WHERE clauses of queries
o the column is unique and is used only with equality predicates