藏在表分区统计信息背后的小秘密

曾令军
云和恩墨技术专家,8年数据库运维经验。思维敏捷,擅长于数据库开发、解决棘手的数据库故障和性能问题,在数据库故障诊断、运维监控、性能优化方面积累了丰富的经验。

本文由一个表分区统计信息没有按预期更新的问题,逐步深入设疑、探因、求实,解开关于表分区统计信息收集的秘密。曲径通幽处,禅房花木深。让我们打开数据库知识的那扇窗,去看到花木浓茂幽静自然的美好。

案例背景

客户的业务系统中,做了AB表设计。A代表日间业务表,只存放一天的交易数据;B代表历史数据表,每天一个分区。每天晚上A表的所有数据会转入B表的最大分区中,然后B表的最大分区分裂成当天分区和新的最大分区。

在做完上述数据转换及分区拆分之后,虽然此时P_20170101这个分区有大量的数据,虽然自动收集统计信息的任务每天都会运行,但这个分区的统计信息始终为0。

【问题】:在数据库自动收集统计信息任务运行后,分区P_20170101的统计信息错误,导致执行计划选择错误,与历史数据有关联的查询运行特别缓慢。

场景模拟

创建历史数据表,按交易日期做范围分区:

插入10000行数据后提交,模拟业务表数据转入历史表:

检查分区的统计信息:

此时虽然插入了数据,但没有手动或自动收集过,因此统计信息仍然为空。

且让它保持为空,并在这个前提下,继续往下做。

接下来拆分分区,然后再次检查分区的统计信息:

拆分完成之后,原分区PEVER和新分区P20170821此时的num_rows均为空。

调用自动收集统计信息任务的过程,然后检查分区的统计信息:

小贴士:dbms_stats.gather_database_stats_job_proc过程就是自动收集统计信息任务执行的程序,此处手工调用,模拟客户数据库每天自动收集任务的运行。该过程相当于使用gather auto选项调用了dbms_stats.gather_database_stats过程

注意此时统计的P20170821记录数为10000行,统计信息完全正确!并没有模拟出与客户问题相符的现象。

继续插入20000行数据,但日期换成20170822,模拟第二天的交易:

拆分分区,然后检查分区的统计信息:

注意这里的差异,新分区P20170822的num_rows并不是空,而是0。

调用自动收集统计信息任务的过程,然后检查分区的统计信息:

问题模拟出来了。新分区P20170822实际上有20000行数据,但自动收集的任务运行后,该分区的行数仍然是0。

模拟过程中引出来的问题:
1) 为什么拆分分区的初始化统计信息开始是空,而后面又变成 0?
2) 为什么分区的统计信息为空时,自动收集任务运行后,统计信息更新了?
3) 为什么分区的统计信息为0时,这个分区有大量数据,而统计信息始终不更新?
4) PEVER分区一开始是空,先插入了20000行,然后数据又分裂出去,重新变回一个空分区,为什么它的统计信息又更新了?

后三个问题,都指向了同一个问题:自动收集任务运行时,哪些对象被收集?

拨开迷雾

问:为什么拆分分区的初始化统计信息开始是空,而后面又变成0?

答:分区分裂时,新分区的统计信息继承了原分区的统计信息值

第一次分裂的时候,由于PEVER分区的统计信息为空,因此分裂出来的P20170821和新的PEVER分区初始的统计信息也为空;第二次分裂的时候,由于此时PEVER分区的统计信息被收集过,变成了 0行,那么分裂出来的P20170821和新的PEVER分区的初始统计信息就是0行。那假如PEVER分区是10000行,新分区也会是10000行,依此类推。

问:自动收集任务运行时,哪些对象被收集?

答:存在缺失和陈旧的统计信息的表、索引、分区

自动收集任务运行时,优先收集缺失统计信息的对象,然后再收集陈旧统计信息的对象。缺失或陈旧统计信息的对象,可以从dba_tab_statistics和dba_ind_statistics这两个视图中查询。

问:如何判断对象的统计信息为陈旧?

答:表或分区的数据变化量超过10%

控制统计信息是否陈旧的数据变化量的比例默认为10%,可通过dbms_stats.get_prefs这个函数查询,这个值也可通过DBMS_STATS.SET_GLOBAL_PREFS修改,但一般不建议这样做。

问题分析到这里,之前提出来的四个问题的答案就已经全部解开了。

为什么拆分分区的初始化统计信息开始是空,而后面又变成 0 ?
----分裂出来的分区继承原分区的统计信息
为什么分区的统计信息为空时,自动收集任务运行后,统计信息更新了?
----缺失统计信息的对象,会被收集
为什么分区的统计信息为0时,这个分区有大量数据,而统计信息始终不更新?
----不满足缺失或陈旧的条件,不被收集
PEVER分区一开始是空,先插入了20000行,然后数据又分裂出去,重新变回一个空分区,为什么它的统计信息又更新了?
----陈旧统计信息的对象,会被收集

那么这个案例如何优化呢?有两种选择都可以解决问题:

a) 修改程序逻辑顺序:先插入数据再SPLIT分区 修改为 先SPLIT分区再插入数据
b) 手动补充收集一次:原业务逻辑不变,但操作完之后,对split出来的分区单独收集

知识扩展

莎士比亚说:大海有崖岸,热烈的爱却没有边界。虽然问题已经解决,仔细思考,还有更多细致的问题在等着我们去探索:

1、如何查询对象的数据变化量?
2、对象的数据变化是如何刷新的?
3、分区表统计信息的更新机制?如果整个分区表的数据更新,会不会扫描那些没有发生数据变化的分区呢?

如何查询对象的数据变化量?

oracle提供了一个名为USER_TAB_MODIFICATIONS的视图,可以查询到分区以及分区表的DML操作次数,例如:


select * from dba_tab_modifications wheretable_name='T_HISTDATA_PART';

这个视图还能查询到对象被truncate的次数。但是存在一个问题:数据修改之后,并不能马上在视图中查询到,需要手工刷新:


begin
    dbms_stats.flush_database_monitoring_info();
end;

数据修改不能立即刷新的原因,就是下面要讨论的问题。

对象的数据变化是如何刷新的?

USER_TAB_MODIFICATIONS的刷新机制

在10G之后,USER_TAB_MODIFICATIONS视图的数据并不能立即更新,而是每天只更新一次,因此需要通过这个视图准确查询到数据变化时,需要先手工刷新。

分区表统计信息的更新机制?

当分区的数据变化达到10%,自动收集统计信息任务运行时,会更新该分区的统计信息。
当分区表中所有分区中数据变化量的总和达到分区表总数据量的10%,会更新该分区表的统计信息。
分区表的统计信息收集更新时,以前必须要扫描该表所有的分区或整个表的数据,在10.2.0.5版本之后,可以设置分区表按增量变化统计,只收集有数据变化的分区。

要设置分区表按增量变化统计,可以设置表统计信息的incremental属性。

【学以致用】:对于一些数据量特别大的分区表,可以考虑设置INCREMENTAL=TRUE属性,能够显著提升分区表统计信息收集的速度。

不闻不若闻之,闻之不若见之,见之不若知之,知之不若行之。通过一个问题的深入剖析,逐层推进,我们看见了、理解了、实践了,最终也收获了。以上这些知识要点,在运维实战中,具备非常有价值的指导意义。

原文发布时间为:2017-09-19
作者:曾令军
本文来自合作伙伴“数据和云”,了解相关信息可以关注“数据和云”微信公众号

时间: 2024-08-01 13:20:07

藏在表分区统计信息背后的小秘密的相关文章

PostgreSQL Analyze分区表:主表与子表的统计信息问题

  最近在PostgreSQL的Mail List中参与讨论了一个问题: ANALYZE'ing table hierarchies.   网友认为在Analyze分区表的时候,只能看到主表的analyze日期更新到最新,但是子表的日期没有变化,他认为analyze应该是在分析主表的时候会将与之相关的子表一起更新.     为此测试了一下,发现无论主表还是子表,需要单独的对其进行analyze才可以更新其最新的统计信息.   以下是实验部分:    music=> create table mu

[20130918]12C表统计信息的在线收集.txt

[20130918]12C表统计信息的在线收集.txt 在12c以前,如果使用ctas建立表,并不会自动收集表的统计信息,12c开始CTAS和IAS操作会收集统计信息.但是不收集直方图信息.以及索引统计. 摘要:twp-bp-for-stats-gather-12c-1967354.pdfBest Practices for Gathering Optimizer Statistics with Oracle Database 12c P16-17页: Online statistics gat

truncate表,会将统计信息清除么?

看见微信群有位朋友问: truncate表,会将统计信息清除么? 有些朋友回复, 数据字典信息都没有了,统计信息就清除了,所以是没有统计信息的. 做个实验,跟踪一下truncate,应该比较清楚. 我做了10g的测试,发现那个表的last_analyzed还是有记录的. truncate完统计信息还是在的,跟你10g还是11g没有关系,关键在你之前有没有收集统计信息,你之前都没有收集统计信息,last analyzed本来就是空的. 之前有记录,last_analyzed是不为空的,trunca

Oracle的统计信息简介

1.什么是统计信息 统计信息主要是描述数据库中表,索引的大小,规模,数据分布状况等的一类信息.比如,表的行数,块数,平均每行的大小,索引的leaf blocks,索引字段的行数,不同值的大小等,都属于统计信息.CBO正是根据这些统计信息数据,计算出不同访问路径下,不同join 方式下,各种计划的成本,最后选择出成本最小的计划. 统计信息是存放在数据字段表中的,如tab$.一般我们从数据字段视图中察看统计信息状况,如DBA_TABLES,DBA_INDEXES,DBA_TAB_COL_STATIS

Oracle统计信息和dbms_stats包

1.统计信息的作用 Oracle基于CBO的优化器在生成执行计划时,很大程度上依赖 于统计信息,你可以把CBO理解为一个复杂的数学模型,而统计信息是它最主要的输入,执行 计划是输出,如果输入都不准确,输出还可能准确吗?所有,统计信息是否及时有效对执行 计划的好坏有着关键的影响. 2.dbms_stats包 Oracle里采用dbms_stats包分 析统计信息(Analyze命令已过时,不建议使用),该包的使用方法,官方文档有详细说明 (http://docs.oracle.com/cd/E11

oracle收集统计信息

什么是统计信息 统计信息主要是描述数据库中表,索引的大小,规模,数据分布状况等的一类信息.比如,表的行数,块数,平均每行的大小,索引的leaf blocks,索引字段的行数,不同值的大小等,都属于统计信息.CBO正是根据这些统计信息数据,计算出不同访问路径下,不同join 方式下,各种计划的成本,最后选择出成本最小的计划. 统计信息是存放在数据字段表中的,如dba_tab_statistics 如何搜集统计信息 统计信息搜集也是有多种方法,推荐大家使用DBMS_STATS 表来进行统计信息搜集及

Oracle 12c数据库优化器统计信息收集的最佳实践

Oracle 12c数据库优化器统计信息收集的最佳实践 转载自     沃趣科技(ID:woqutech)  作者         刘金龙(译) 原文链接   http://www.oracle.com/technetwork/database/bi-datawarehousing/twp-bp-for-stats-gather-12c-1967354.pdf 导  语 Oracle优化器会为SQL语句产生所有可能的访问路径(执行计划),然后从中选择一条COST值最低的执行路径,这个cost值是

统计信息不准确导致执行计划走了笛卡尔积

统计信息不准确导致执行计划走了笛卡尔积   昨天有事没有上班,今天早上来查看系统的时候发现了很多笛卡尔积的sql,而且一直在跑,已经运行了10多个小时了,觉得这个比较典型,这里记录一下:   SELECT a.ELAPSED_TIME 已运行时间,a.MONITOR_TYPES,a.SQL_ID,a.SQL_TEXT FROM XT_SQL_RUBBISH_MONITOR_LHR a WHERE a.MONITOR_TYPES = '笛卡尔积监控' and a.ID>=45150 ORDER B

ORACLE SQL调优之统计信息缺失导致的逻辑读暴增

    2016年11月8日,接到广西负责人申告,说决策系统一条SQL平时执行2s左右能执行完,现在却要执行2:30多才能出结果,请求对其做处理.     操作系统:RHEL LINUX 6.4     数据库版本:11.2.0.4     首先,登录服务器查看数据库服务器的状态: [oracle@orcl ~]$ free -m              total       used       free     shared    buffers     cached Mem: