基于湖库一体架构,统一管理结构化、半结构化与非结构化等多模态数据,一个系统承载事务处理、实时分析与 AI 工作负载。
OceanBase Oracle 租户下 user_tables/all_tables 的 num_rows 与实际数据量不一致
更新时间:2026-08-21 07:56
问题现象
在日常运维或监控中,发现 user_tables、all_tables 或 dba_tab_statistics 等视图中的 num_rows 字段值与表的实际行数存在显著差异。
问题原因
统计信息非实时更新
num_rows 的值并非实时计算得出,而是上一次收集统计信息时写入的元数据。OceanBase 的自动统计信息收集策略如下:
- 后台自动收集任务仅在统计信息被判定为"过期(stale)"时才会触发。
- 默认的过期判定阈值为
STALE_PERCENT = 10%。这意味着,当表的 DML 变更行数占当前统计行数的比例未达到 10% 时,不会触发自动收集。 - 因此,即使表在持续写入数据,只要未达到 10% 的变更比例,
num_rows就会保持旧值,导致与实际数据量不一致。
新表或无统计信息表
如果表从未收集过统计信息,或者统计信息已被清理,则 num_rows 可能为 NULL。
备租户无独立收集
备租户不会主动收集统计信息,其统计信息完全从主租户同步。因此,备租户的 num_rows 始终与主租户保持一致。
关键信息
确认统计信息是否过期
查询 dba_tab_statistics 视图,查看 num_rows、last_analyzed 及 stale_stats 标记:
SELECT owner,
table_name,
num_rows,
last_analyzed,
stale_stats
FROM dba_tab_statistics
WHERE owner = 'YOUR_SCHEMA'
AND table_name = 'YOUR_TABLE';
last_analyzed:上次收集统计信息的时间。stale_stats:标记统计信息是否已过期(YES表示已过期)。
查看表级过期详情
在 Oracle 租户下,可通过 SYS.DBA_OB_TABLE_STAT_STALE_INFO 视图查看表的统计信息过期状态:
SELECT * FROM SYS.DBA_OB_TABLE_STAT_STALE_INFO
WHERE TABLE_NAME = 'YOUR_TABLE';
查询当前过期阈值
查看全局或表级的 STALE_PERCENT 配置:
-- 查询全局默认值
SELECT dbms_stats.get_prefs('STALE_PERCENT', 'SYS') FROM dual;
-- 查询特定表的配置
SELECT dbms_stats.get_prefs('STALE_PERCENT', 'YOUR_SCHEMA', 'YOUR_TABLE') FROM dual;
默认值为 10(即 10%)。
问题的风险及影响
| 风险项 | 说明 |
|---|---|
| 业务监控失真 | 基于 num_rows 的表大小监控、数据量统计报表不准确。 |
| 执行计划偏差 | 陈旧的统计信息会导致优化器选择次优执行计划,影响查询性能。 |
影响租户
Oracle 模式租户。
适用版本
OceanBase 数据库 3.x / 4.x Oracle 租户模式。
解决方法
手动收集统计信息(推荐应急)
在业务低峰期执行以下命令,对指定表收集统计信息:
CALL dbms_stats.gather_table_stats(
ownname => 'YOUR_SCHEMA',
tabname => 'YOUR_TABLE',
granularity => 'GLOBAL',
method_opt => 'FOR ALL COLUMNS SIZE AUTO'
);
注意事项:
- 收集前建议在 Session 级别调大
ob_query_timeout,防止大表收集超时中断:
SET SESSION ob_query_timeout = 3600000000;
- 大表收集会消耗 CPU 和 I/O 资源,应避免在业务高峰期执行。
通过 OCP 收集统计信息
在 OCP 控制台的操作路径如下:
- 进入对应租户页面。
- 点击 统计信息管理 模块。
- 选择需要收集的表,点击 收集统计信息。
OCP 收集同样受 ob_query_timeout 限制,若表较大请提前调整超时参数。
调整特定表过期阈值(按需)
如果某些核心业务表对统计信息准确性要求较高,可适当调低该表的 STALE_PERCENT。
-- 设置单表阈值为 5%
CALL dbms_stats.set_table_prefs('YOUR_SCHEMA', 'YOUR_TABLE', 'STALE_PERCENT', '5');
-- 验证
SELECT dbms_stats.get_prefs('STALE_PERCENT', 'YOUR_SCHEMA', 'YOUR_TABLE') FROM dual;
调整全局过期阈值(按需)
不建议将全局阈值调得过小,以免自动收集任务频繁触发导致资源争抢。
-- 修改全局默认值
CALL dbms_stats.set_global_prefs('STALE_PERCENT', '5');
-- 验证
SELECT dbms_stats.get_prefs('STALE_PERCENT', 'SYS') FROM dual;
规避方式
定期手动收集大表统计信息
对于业务需要统计且数据变化频繁的大表,建议建立定期维护窗口,在低峰期通过脚本批量收集:
-- 示例:收集指定 Schema 下所有表的统计信息
BEGIN
FOR rec IN (
SELECT table_name FROM user_tables
WHERE num_rows > 8000000 OR num_rows IS NULL
) LOOP
dbms_stats.gather_table_stats(
ownname => USER,
tabname => rec.table_name,
granularity => 'GLOBAL',
method_opt => 'FOR ALL COLUMNS SIZE AUTO'
);
END LOOP;
END;
/
监控统计信息新鲜度
建议将以下查询加入日常巡检,及时发现长期未更新的统计信息:
SELECT owner,
table_name,
num_rows,
last_analyzed,
stale_stats
FROM dba_tab_statistics
WHERE num_rows IS NULL
OR last_analyzed < SYSDATE - 7
ORDER BY last_analyzed;