基于湖库一体架构,统一管理结构化、半结构化与非结构化等多模态数据,一个系统承载事务处理、实时分析与 AI 工作负载。
统计信息
更新时间:2026-08-14 17:23:24
在数据库中,优化器针对每一个输入的 SQL 查询都会尝试生成最优的执行计划,而生成最优的执行计划往往需要实时有效的统计信息和准确的行数估计。统计信息实际上指的是优化器统计信息(optimizer statistics),它是一个描述数据库中表和列信息的数据集合,是代价模型选取最优执行计划的非常关键的部分。优化器代价模型(optimizer cost model)依赖于查询中涉及到的表、列、谓词等对象的统计信息来选取计划、优化计划的选择。准确有效的统计信息能够帮助优化器选择到最优的执行计划。
OceanBase Database AI 支持对内表(本地表)以及外部 Catalog 表(如 Hive、Iceberg 格式的外表)进行统计信息的收集与管理,涵盖表级、列级基础统计信息和直方图等类型,并提供定时自动收集、手动收集、在线收集、异步自动收集等多种策略。
内表统计信息
在大多数系统中,用户通常无需关注统计信息的具体问题,因为优化器会定期执行任务以收集需要更新的表的统计信息。然而,AP 场景中可能存在一些超大表,或大批量更新后提供实时查询的表,这时使用默认的统计信息收集策略可能无法及时完成统计信息的收集,进而影响执行计划的生成。下文将对 AP 部分场景如何收集统计信息做些针对性介绍。
统计信息的分类
统计信息主要可分为以下几类:
表级(包括索引表)统计信息:包括行数、宏块数、微块数、平均行长等,用于估算表的扫描代价。
列级统计信息
- 列值分布:最大值、最小值、平均列长和不同值个数(NDV)。
- 数据倾斜:通过频率分布(Histogram)描述数据的分布情况。
- 空值率:帮助优化器处理与 NULL 值相关查询。
OceanBase 支持的统计信息收集方式
自动收集:优化器定时任务,默认每天分析表是否需要更新统计信息。
手动收集:用户可使用 SQL 命令触发统计信息收集,适合超大表或特定查询优化。并且,用户收集统计信息时,可以指定收集策略,比如收集的并行度、收集的粒度、收集直方图桶个数配置等等。
在线收集:批量导入、PDML、
CREATE TABLE ... AS等场景可以通过GATHER_OPTIMIZER_STATISTICSHint 和系统变量_optimizer_gather_stats_on_load(默认开启)进行在线统计信息收集,同时也可以使用旁路导入功能的APPENDHint 实现在线统计信息收集。
统计信息的更新机制
阈值触发更新:当表数据变化超过一定比例时(默认数据量变化超过 10 倍),触发统计信息异步更新。
分区表支持:OceanBase 支持分区级别的统计信息更新与管理。
统计信息在 AP 场景中的优化策略
定制化收集策略
- 选择性收集:针对 AP 场景的核心查询表或关键列,单独配置收集任务。
- 分区优先:优先更新使用频率最高或变化最大的分区。
配置并行度
- 为超大表收集统计信息时,合理配置收集并行度。
动态调整更新频率
- 基于表数据的更新模式,灵活配置统计信息更新频率,避免不必要的开销。
场景示例
调整统计信息收集窗口
默认情况下,OceanBase 优化器通过维护窗口来进行每日自动统计信息收集,从而保证统计信息能够迭代更新。周一到周日的任务默认开始时间为 22:00,最大收集时长 4 小时,如下表所示。
| 维护窗口名称 | 开始时间/频率 | 最大收集时长 |
|---|---|---|
| MONDAY_WINDOW | 22:00/per week | 4 hours |
| TUESDAY_WINDOW | 22:00/per week | 4 hours |
| WEDNESDAY_WINDOW | 22:00/per week | 4 hours |
| THURSDAY_WINDOW | 22:00/per week | 4 hours |
| FRIDAY_WINDOW | 22:00/per week | 4 hours |
| SATURDAY_WINDOW | 22:00/per week | 4 hours |
| SUNDAY_WINDOW | 22:00/per week | 4 hours |
我们需要根据业务的实际情况合理的配置维护窗口。例如当维护窗口刚好与业务高峰重合,可以调整维护窗口的开始时间,或者在特定日期不做统计信息收集。当业务环境中表的数量很多,或存在很多超大表的时候,可以调整维护窗口的收集时长。
下面是一些配置示例。
-- 禁用周一自动收集统计信息
CALL DBMS_SCHEDULER.DISABLE('MONDAY_WINDOW');
-- 启用周一自动收集统计信息
CALL DBMS_SCHEDULER.ENABLE('MONDAY_WINDOW');
-- 设置周一自动收集统计信息开始的时间在晚上8点
CALL DBMS_SCHEDULER.SET_ATTRIBUTE('MONDAY_WINDOW', 'NEXT_DATE', '2022-09-12 20:00:00');
-- 设置周一自动收集统计信息的持续时长为6小时
-- 6小时 <=> 6 * 60 * 60 * 1000 * 1000 <=> 21600000000 us
CALL DBMS_SCHEDULER.SET_ATTRIBUTE('WEDNESDAY_WINDOW', 'JOB_ACTION', 'DBMS_STATS.GATHER_DATABASE_STATS_JOB_PROC(21600000000)');
超大表统计信息收集策略
存在超大表的场景下,优化器的默认统计信息收集策略可能会导致表的统计信息在一次维护窗口中收集不完。因此需要针对超大表设置合理的收集策略。在收集超大表的统计信息时,耗时的地方主要有三个:
- 表数据量大,收集需要全表扫,耗时高。
- 直方图收集涉及复杂的计算,带来额外成本的耗时。
- 大分区表默认收集二级分区、一级分区、全表的统计信息和直方图,3 * (cost(全表扫)+cost(直方图))代价
根据上述耗时点,可以根据表的实际情况及相关查询情况进行优化。建议如下:
设置合适的默认收集并行度,需要注意的是设置并行度之后,需要调整相关的自动收集任务在业务低峰期进行,避免影响业务,建议并行度控制 8 个以内,可使用如下方式设置。
CALL DBMS_STATS.SET_TABLE_PREFS('database_name', 'table_name', 'degree', '8');设置默认列的直方图收集方式,考虑给数据分布均匀的列设置不收集直方图。
-- 1.如果该表所有列的数据分布都是均匀的,可以使用如下方式设置所有列都不收集直方图: CALL DBMS_STATS.SET_TABLE_PREFS('database_name', 'table_name', 'method_opt', 'for all columns size 1'); -- 2.如果该表仅极少数列数据分布不均匀,需要收集直方图,其他列都不需要,则可以使用如下方式设置(c1,c2 收集直方图,c3,c4,c5 不收集直方图) CALL DBMS_STATS.SET_TABLE_PREFS('database_name', 'table_name', 'method_opt', 'for columns c1 size 254, c2 size 254, c3 size 1, c4 size 1, c5 size 1');设置默认分区表的收集粒度,针对一些分区表,形如 hash 分区/key 分区之类的,可以考虑只收集全局的统计信息,或者也可以设置分区推导全局的收集方式。
-- 1.设置只收集全局的统计信息 CALL DBMS_STATS.SET_TABLE_PREFS('database_name', 'table_name', 'granularity', 'GLOBAL'); -- 2.设置分区推导全局的收集方式 CALL DBMS_STATS.SET_TABLE_PREFS('database_name', 'table_name', 'granularity', 'APPROX_GLOBAL AND PARTITION');慎用设置大表采样的方式收集统计信息,设置大表采样收集时,早期版本直方图的样本数量也会变得很大,存在适得其反的效果,设置采样的方式收集仅仅适合只收集基础统计信息,不收集直方图的场景。
-- 1.设置所有列都不收集直方图: CALL DBMS_STATS.SET_TABLE_PREFS('database_name', 'table_name', 'method_opt', 'for all columns size 1'); -- 2.设置采样比例为 10% CALL DBMS_STATS.SET_TABLE_PREFS('database_name', 'table_name', 'estimate_percent', '10');
除此之外,如果需要清空/删除已设置的默认收集策略,只需要指定清除的属性即可 {attribute},使用如下方式。
CALL DBMS_STATS.delete_table_prefs('database_name', 'table_name', 'granularity');
如果设置好了相关收集策略,需要查询是否设置成功,可以使用如下方式查询。
SELECT DBMS_STATS.GET_PREFS('degree', 'database_name','table_name') from dual;
除了上述方式以外,也可以考虑能否手动收集完大表统计信息之后,锁定相关的统计信息。需要注意的是当表的统计信息锁定之后,自动收集将不会更新,适用于一些对数据特征变化不太大、数据值不敏感的场景,如果需要重新收集锁定的统计信息,需要先将其解锁。
CALL DBMS_STATS.LOCK_TABLE_PREFS('database_name', 'table_name');
CALL DBMS_STATS.UNLOCK_TABLE_PREFS('database_name', 'table_name');
HMS Catalog 外表统计信息收集策略
OceanBase Database AI 通过扩展 DBMS_STATS 包,新增 GATHER_CATALOG_TABLE_STATS 等接口,支持对 HMS Catalog 中的外表(Hive/Iceberg 格式)收集表级与列级统计信息。优化器可利用这些统计信息为外表查询选择更优的执行计划(如 JOIN 顺序、并行度等),显著提升外表查询性能。
功能介绍
统计信息类型
支持收集以下统计信息:
| 级别 | 内容 | 说明 |
|---|---|---|
| 表级 | 行数、平均行长度、文件数、数据大小 | 支持全局和分区级别 |
| 列级 | NDV(distinct 值数)、NULL 数、最大/最小值、平均列长 | 支持全局和分区级别 |
锁统计信息
支持锁定指定表或分区的统计信息,防止被后续的收集操作覆盖,典型用于稳定环境中固定执行计划。
支持的格式
- Hive Parquet/ORC/CSV 表
- Iceberg 表
使用限制
- 目前仅支持 HMS Catalog 中的 Hive 格式表(Parquet/ORC/CSV),Iceberg 格式已支持统计信息收集但暂不支持分区枚举。
- 统计信息存储在 OceanBase Database AI 内部系统表中,不会写回 HMS。
- 不支持 CDC/SCN 快照读(外表本身不支持该特性)。
- 收集操作是同步执行的,大表可能耗时较长,建议在业务低峰期执行。
操作步骤
步骤一:收集全局统计信息
对 HMS Catalog 中的外表收集全局(表级+列级)统计信息。
收集 lineitem 表的统计信息:
obclient> CALL DBMS_STATS.GATHER_CATALOG_TABLE_STATS(
'hive_catalog', -- catalog 名称
'test_oss', -- database 名称
'lineitem', -- 表名
NULL, -- 分区名,NULL 表示全表
100, -- 采样百分比,100 表示全量
'BLOCK', -- 采样方式,BLOCK 表示块采样
NULL, -- method_opt,NULL 使用默认
32 -- 并行度
);
更多关于 DBMS_STATS.GATHER_CATALOG_TABLE_STATS 的介绍信息,参见 GATHER_CATALOG_TABLE_STATS。
步骤二:查看收集结果
查看表级统计信息。
obclient> SELECT * FROM oceanbase.DBA_OB_EXTERNAL_TAB_STATISTICS WHERE catalog_name = 'hive_catalog' AND database_name = 'test_oss' AND table_name = 'lineitem';更多关于
oceanbase.DBA_OB_EXTERNAL_TAB_STATISTICS的介绍信息,参见 oceanbase.DBA_OB_EXTERNAL_TAB_STATISTICS。查看列级统计信息(全局)。
obclient> SELECT * FROM oceanbase.DBA_OB_EXTERNAL_TAB_COL_STATISTICS WHERE catalog_name = 'hive_catalog' AND database_name = 'test_oss' AND table_name = 'lineitem';更多关于
oceanbase.DBA_OB_EXTERNAL_TAB_COL_STATISTICS的介绍信息,参见 oceanbase.DBA_OB_EXTERNAL_TAB_STATISTICS。查看分区列统计信息。
obclient> SELECT * FROM oceanbase.DBA_OB_EXTERNAL_PART_COL_STATISTICS WHERE catalog_name = 'hive_catalog' AND database_name = 'test_oss' AND table_name = 'lineitem';更多关于
oceanbase.DBA_OB_EXTERNAL_PART_COL_STATISTICS的介绍信息,参见 oceanbase.DBA_OB_EXTERNAL_PART_COL_STATISTICS。
步骤三:收集指定分区的统计信息
obclient> CALL DBMS_STATS.GATHER_CATALOG_TABLE_STATS(
'hive_catalog',
'test_oss',
'lineitem',
'l_shipdate=1998-01-01', -- 指定分区
100,
'BLOCK',
NULL,
32
);
更多关于 DBMS_STATS.GATHER_CATALOG_TABLE_STATS 的介绍信息,参见 GATHER_CATALOG_TABLE_STATS。
步骤四:设置收集参数
通过 SET_CATALOG_TABLE_PREFS 调整分区批处理大小:
将分区批处理大小设为 64。
obclient> CALL DBMS_STATS.SET_CATALOG_TABLE_PREFS( 'hive_catalog', 'test_oss', 'lineitem', 'CATALOG_STATS_BATCH_SIZE', '64' );更多关于
DBMS_STATS.SET_CATALOG_TABLE_PREFS的介绍信息,参见 SET_CATALOG_TABLE_PREFS。查看当前设置。
obclient> SELECT DBMS_STATS.GET_CATALOG_PREFS( 'CATALOG_STATS_BATCH_SIZE', 'hive_catalog', 'test_oss', 'lineitem' );更多关于
DBMS_STATS.GET_CATALOG_PREFS的介绍信息,参见 GET_CATALOG_PREFS。删除设置(恢复默认值)。
obclient> CALL DBMS_STATS.DELETE_CATALOG_TABLE_PREFS( 'hive_catalog', 'test_oss', 'lineitem', 'CATALOG_STATS_BATCH_SIZE' );更多关于
DBMS_STATS.DELETE_CATALOG_TABLE_PREFS的介绍信息,参见 DELETE_CATALOG_TABLE_PREFS。
步骤五:锁定与解锁统计信息
锁定表统计信息(禁止自动刷新)。
obclient> CALL DBMS_STATS.LOCK_CATALOG_TABLE_STAT( 'hive_catalog', 'test_oss', 'lineitem' );更多关于
DBMS_STATS.LOCK_CATALOG_TABLE_STAT的介绍信息,参见 LOCK_CATALOG_TABLE_STAT。解锁。
obclient> CALL DBMS_STATS.UNLOCK_CATALOG_TABLE_STAT( 'hive_catalog', 'test_oss', 'lineitem' );更多关于
DBMS_STATS.UNLOCK_CATALOG_TABLE_STAT的介绍信息,参见 UNLOCK_CATALOG_TABLE_STAT。
步骤六:强制全量重新收集
当需要忽略新鲜度检测、强制重新收集所有分区的统计信息时,指定 force => TRUE:
obclient> CALL DBMS_STATS.GATHER_CATALOG_TABLE_STATS(
'hive_catalog',
'test_oss',
'lineitem',
NULL,
100,
'BLOCK',
NULL,
32,
'DEFAULT', -- granularity
TRUE -- force,强制全量收集
);
更多关于 DBMS_STATS.GATHER_CATALOG_TABLE_STATS 的介绍信息,参见 GATHER_CATALOG_TABLE_STATS。
相关文档
有关统计信息的详细介绍和使用指导,可以查看以下文档:
统计信息包含表统计信息(Table Level Statistics)和列统计信息(Column Level Statistics)两种类型,更多关于统计信息类型的介绍,参见 统计信息概述。
OceanBase Database AI 优化器支持手动收集统计信息和自动收集统计信息,有关统计信息收集的详细介绍和操作指导,参见 统计信息收集方式概述。
关于统计信息管理的详细操作指导,参见 统计信息管理 章节。
通过一个简单的示例了解统计信息的使用,查看示例。