直接对单个分区执行gather_table_stats不会触发增量逻辑,因incremental=true仅在granularity为'all'或'auto'的全局收集时生效,且依赖synopsis链完整性;必须先以granularity=>'all'初始化 synopsis,再启用incremental才能实现真正的增量统计。

直接对单个分区执行 GATHER_TABLE_STATS 不会触发增量逻辑
Oracle 的 INCREMENTAL = TRUE 机制只在全局级收集(GRANULARITY 为 'AUTO' 或 'ALL')时生效,且依赖 synopsis 链的完整性。若你只传入 partname => 'P20240825',哪怕同时设了 incremental => 'TRUE',DBMS_STATS 也会忽略该参数——它此时走的是纯分区级路径,不读 synopsis,也不合并全局统计。
常见错误现象:LAST_ANALYZED 更新了,但 DBA_TAB_PARTITIONS.NUM_ROWS 没变、DBA_TABLES.NUM_ROWS 仍是旧值,查询计划照旧走错。
- 必须用
granularity => 'ALL'或'AUTO'触发全局扫描入口 -
partname参数不能和INCREMENTAL同时用于“单分区提速”目的——它俩设计上互斥 - 真正能“只扫一个分区”的方式,是先确保 synopsis 链已建好,再靠
INCREMENTAL自动识别变更分区
INCREMENTAL 生效前必须先跑一次 granularity => 'ALL'
已有陈旧统计的表,直接开 INCREMENTAL 不会补 synopsis,后续所有增量收集都只是“假装更新”,全局统计值卡死不动。必须显式执行一次全粒度初始化:
EXEC DBMS_STATS.GATHER_TABLE_STATS( ownname => 'SCHEMA_NAME', tabname => 'TABLE_NAME', granularity => 'ALL', estimate_percent => DBMS_STATS.AUTO_SAMPLE_SIZE, degree => 4 );
这一步会把当前每个分区的列级摘要(synopsis)写入 WRI$_OPTSTAT_SYNOPSIS$,建立初始链。耗时接近全量收集,但只需一次。
- 跳过此步 → 后续
INCREMENTAL收集后DBA_TABLES.NUM_ROWS仍为 NULL 或旧值 - 验证是否成功:查
SELECT COUNT(*) FROM sys.wri$_optstat_synopsis$ WHERE bo# = (SELECT object_id FROM dba_objects WHERE object_name = 'TABLE_NAME'),结果应 ≥ 分区数 × 列数 - 初始化后,再改回
INCREMENTAL => 'TRUE'才真正启用增量
如何让 Oracle 只收集你刚插入数据的那个分区?
Oracle 不会因为你“刚 INSERT 了一天的数据”就自动知道哪几个分区变了——它靠内部变更跟踪(STALE_STATS 标记 + 块级变更位图)判断,但默认不开启。所以实际操作中,你要主动缩小范围:
- 先确认目标分区确实有数据变动:
SELECT PARTITION_NAME, NUM_ROWS, LAST_ANALYZED, STALE_STATS FROM DBA_TAB_PARTITIONS WHERE TABLE_NAME = 'TABLE_NAME' AND PARTITION_NAME IN ('P20240825', 'P20240826') - 若
STALE_STATS = 'YES',说明 Oracle 已感知到变更;否则需手动标记:DBMS_STATS.LOCK_PARTITION_STATS后再UNLOCK强制置脏(慎用) - 然后执行全局收集,但限定采样范围:
EXEC DBMS_STATS.GATHER_TABLE_STATS(ownname=>'SCHEMA_NAME', tabname=>'TABLE_NAME', incremental=>TRUE, granularity=>'AUTO') - Oracle 此时会扫描所有分区的变更位图,仅对
STALE_STATS = 'YES'的分区做实际扫描,其余复用 synopsis
哈希分区表别硬上 INCREMENTAL
哈希分区天然数据均匀分布,新插入数据大概率打散到全部分区。这时 INCREMENTAL = TRUE 不仅不省时间,反而因维护 synopsis 多出额外解析与合并开销,实测比 granularity => 'ALL' 全量还慢。
范围/列表分区才适合增量:每天只新增一个分区,或批量更新固定几个历史分区,其余长期不变。
- 验证是否适合:查
SELECT PARTITION_NAME, LAST_ANALYZED FROM DBA_TAB_PARTITIONS WHERE TABLE_NAME = 'TABLE_NAME' ORDER BY LAST_ANALYZED,如果多个分区LAST_ANALYZED时间接近且频繁变动,说明增量收益极低 - 哈希表建议保持
INCREMENTAL => 'FALSE',改用ESTIMATE_PERCENT => 10加快采样 -
GRANULARITY => 'GLOBAL'是陷阱:它跳过分区扫描,直接重算全局统计,导致 synopsis 链断裂,后续增量永久失效
真正起作用的不是“指定分区”,而是“让 Oracle 自动识别出哪些分区变了”。这背后依赖 synopsis 链、变更跟踪状态、以及粒度参数的精确配合——漏掉任一环,INCREMENTAL 就只是个摆设。











