【问题描述】分区表的统计信息收集有什么讲究?
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 |
分区级统计 + 由分区推导全局 | 大表推荐,避免全表扫描 |
大分区表推荐使用
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 表示未锁定)
总结:分区表统计信息收集的最佳实践
-
日常收集:依赖自动收集机制,确保
STALE_PERCENT阈值合理 -
大表手动收集:使用
APPROX_GLOBAL AND PARTITION粒度 + 适当并行度,避免全表扫描 -
直方图按需收集:不要对所有列都收集直方图,只对数据倾斜的列设置
SIZE 254,其余设SIZE 1 -
超大表采样:设置
estimate_percent或开启block_sample加速收集 - 关键表锁定:调优完成后锁定统计信息,防止被自动任务覆盖
-
定期验证:通过
DBA_TAB_STATISTICS检查stale_stats字段,及时发现过期统计信息