分区表的统计信息收集有什么讲究?

【问题描述】分区表的统计信息收集有什么讲究?

3 个赞

在系统资源允许的情况下,推荐在非分区表原有并行度基础上再增加一倍 。 手动统计信息收集可通过 DBMS_STATS 系统包或 ANALYZE TABLE 语句实现

OceanBase V4 中分区表的统计信息收集确实有不少讲究,核心在于粒度控制、性能平衡和自动化策略三个方面。以下是系统梳理:

V4 与 V3 的关键区别

OceanBase V4 将统计信息收集与每日合并完全解耦,每日合并期间不再负责收集统计信息。 这意味着如果不自建收集机制,统计信息可能长期不更新,导致执行计划劣化。

收集粒度(granularity)

这是分区表统计信息收集最核心的参数,决定了收集哪些层级的统计信息:

granularity 值 收集范围 适用场景
GLOBAL 仅全表级别 不需要分区裁剪的场景
PARTITION 仅各分区级别 只需分区裁剪,不需要全局统计
SUBPARTITION 仅子分区级别 二级分区表的细粒度优化
ALL GLOBAL + PARTITION + SUBPARTITION 最完整,但耗时最长
AUTO(默认) 等同于 ALL 默认行为
DEFAULT GLOBAL + PARTITION 常用折中方案
GLOBAL AND PARTITION 全局 + 分区 与 DEFAULT 类似
APPROX_GLOBAL AND PARTITION 分区级统计 + 由分区推导全局 大表推荐,避免全表扫描

:warning: 大分区表推荐使用 APPROX_GLOBAL AND PARTITION。它会先收集各分区级别的统计信息,再根据分区信息推导出全局统计信息,避免了额外的全表扫描,大幅降低收集成本。

-- 推荐的大分区表收集方式
CALL dbms_stats.gather_table_stats(
    'test', 't_part',
    degree => 2,
    granularity => 'APPROX_GLOBAL AND PARTITION'
);

直方图收集策略(method_opt)

直方图是统计信息中最耗资源的部分,尤其是分区表,每个分区都会单独收集直方图,代价成倍增长。

method_opt 值 含义 适用场景
FOR ALL COLUMNS SIZE 1 所有列不收集直方图 数据分布均匀的表
FOR ALL COLUMNS SIZE AUTO 优化器自动决定是否收集 通用场景(默认)
FOR ALL COLUMNS SIZE SKEWONLY 仅对数据倾斜的列收集 部分列存在倾斜
FOR ALL COLUMNS SIZE 254 所有列都收集直方图 数据分布复杂,需要精确估算
FOR COLUMNS c1 SIZE 254, c2 SIZE 1 指定列分别设置 精确控制,最推荐
-- 仅对数据倾斜列 c1、c2 收集直方图,c3 不收集
CALL dbms_stats.gather_table_stats(
    'test', 't_part',
    granularity => 'APPROX_GLOBAL AND PARTITION',
    method_opt => 'FOR COLUMNS c1 SIZE 254, c2 SIZE 254, c3 SIZE 1'
);

并行度控制(degree)

分区表数据量大,合理设置并行度可以显著加速收集,但过高会冲击在线业务:

-- 数据量小于千万级
CALL dbms_stats.gather_table_stats('test', 't1');

-- 数据量大于千万级,设置并行度
CALL dbms_stats.gather_table_stats('test', 't1', degree => 8);

-- 超大表,高并行度
CALL dbms_stats.gather_table_stats('test', 'big_table', degree => 128);

采样比例控制(estimate_percent)

对于超大分区表,可以设置采样比例来加速收集,牺牲少量精度换取速度:

-- 设置采样比例为 0.1%(适合亿级大表)
CALL dbms_stats.set_table_prefs('test', 'big_part_table', 'estimate_percent', '0.1');

-- 开启块采样(比行采样更快,但精度略低)
CALL dbms_stats.set_table_prefs('test', 'big_part_table', 'block_sample', 'True');

自动统计信息收集

OceanBase V4 提供了自动收集机制,通过定时 JOB 实现:

  • 触发条件:数据修改比例超过阈值(STALE_PERCENT,默认 10%)的表/分区才会被收集
  • 执行时间:工作日 22:00 / 周末 6:00(固定时间窗口)
  • 自动收集范围:未收集过统计信息的表 + 统计信息已过期的表
  • 支持自定义:用户可修改过期规则和执行时间
-- 查看自动收集任务的执行情况
SELECT * FROM DBA_OB_TASK_OPT_STAT_GATHER_HISTORY WHERE TENANT_ID = 1006;

-- 查看表级别的收集历史
SELECT * FROM DBA_OB_TABLE_OPT_STAT_GATHER_HISTORY WHERE OWNER = 'scott';

统计信息锁定与解锁

当某张表的统计信息已经调优到理想状态,可以锁定防止被自动收集覆盖:

-- 锁定表的统计信息
CALL dbms_stats.lock_table_stats('test', 'big_table');

-- 锁定后,gather_schema_stats 会跳过该表
CALL dbms_stats.gather_schema_stats('TEST', degree => 16);

-- 需要更新时先解锁
CALL dbms_stats.unlock_table_stats('test', 'big_table');

查询统计信息状态

收集完成后,可通过以下视图确认统计信息是否到位:

-- 查看表级统计信息(含分区级别)
SELECT owner, table_name, partition_name, num_rows, avg_row_len,
       last_analyzed, stale_stats
FROM DBA_TAB_STATISTICS
WHERE owner = 'test' AND table_name = 't_part';

关键字段说明:

  • last_analyzed:上次收集时间
  • stale_stats:统计信息是否过期(YES 表示需要重新收集)
  • stattype_locked:是否被锁定(NULL 表示未锁定)

:pushpin: 总结:分区表统计信息收集的最佳实践

  1. 日常收集:依赖自动收集机制,确保 STALE_PERCENT 阈值合理
  2. 大表手动收集:使用 APPROX_GLOBAL AND PARTITION 粒度 + 适当并行度,避免全表扫描
  3. 直方图按需收集:不要对所有列都收集直方图,只对数据倾斜的列设置 SIZE 254,其余设 SIZE 1
  4. 超大表采样:设置 estimate_percent 或开启 block_sample 加速收集
  5. 关键表锁定:调优完成后锁定统计信息,防止被自动任务覆盖
  6. 定期验证:通过 DBA_TAB_STATISTICS 检查 stale_stats 字段,及时发现过期统计信息