分区表查询变慢主因是分区裁剪失效、新分区统计信息缺失或hwm残留空块;执行计划无partition range single/iterator而出现table access full即裁剪失败,常见于函数包裹分区键、隐式转换、绑定变量类型不匹配或跨pdb查询未确认容器。

分区表查询变慢,大概率不是SQL写错了,而是分区裁剪没生效、统计信息没覆盖新分区、或者高水位线(HWM)卡在旧分区里——这三类问题占实际案例的八成以上。
查分区裁剪是否失效
Oracle执行计划里看不到PARTITION RANGE SINGLE或PARTITION RANGE ITERATOR,却出现TABLE ACCESS FULL,基本就是裁剪失败。常见原因有:
- WHERE条件里用了函数或表达式,比如
TO_CHAR(part_col, 'YYYY-MM'),导致无法匹配分区键 - 分区键是
DATE类型,但传入的是字符串(如'2025-06'),隐式转换会绕过裁剪 - 用了绑定变量且类型不匹配,比如变量定义为
VARCHAR2但分区键是NUMBER - 查询跨多个PDB,而分区元数据只在当前容器有效,
show con_name确认是否在正确的FREEPDB1里
验证方式:执行EXPLAIN PLAN FOR后查DBMS_XPLAN.DISPLAY,重点看Operation列和Partition Start/Stop字段值是否为KEY或具体分区名。
确认新分区统计信息是否收集
新增分区(比如刚ADD PARTITION或EXCHANGE进来)默认没有统计信息,CBO会按“空表”估算行数,导致选错执行计划。现象是:执行计划里E-Rows显示1或极小值,但实际返回成千上万行。
必须手动触发收集,不能等自动任务:
- 只收集单个分区:
DBMS_STATS.GATHER_TABLE_STATS(ownname=>'SCHEMA', tabname=>'TBL_NAME', partname=>'P_202506') - 收集整个表但跳过已有统计的分区(节省时间):
granularity=>'AUTO'参数 - 避免用
cascade=>TRUE无差别重建所有索引,分区局部索引只需更新对应分区的统计信息
注意:23ai中如果启用了DBMS_STATS.AUTO_TASK,它默认只覆盖最近7天新增分区,老分区仍需人工干预。
检查分区HWM是否残留空块
对某个分区执行过大量DELETE(比如清理历史日志),但没做ALTER TABLE ... MOVE PARTITION,该分区的HWM仍卡在高位。查询时全扫空块,逻辑读暴增。
诊断方法:
- 查
DBA_TAB_PARTITIONS:对比BLOCKS和NUM_ROWS * AVG_ROW_LEN / 8192(假设块大小8K),比值>3说明严重浪费 - 查
V$SEGMENT_STATISTICS中该分区段的db block changes和logical reads是否异常高
收缩操作要分两步:
-
ALTER TABLE t MOVE PARTITION p_202506;—— 降HWM,但会让该分区所有本地索引UNUSABLE -
ALTER INDEX idx_local REBUILD PARTITION p_202506;—— 必须立刻重建,否则后续DML报ORA-01502
别图省事用TRUNCATE PARTITION替代——它清空数据但不重排物理存储,HWM照样不动。
23ai特有风险:向量列+分区混合查询
如果分区表里加了向量列(比如VECTOR(384) STORAGE ON),又在WHERE里混用传统条件和VECTOR_DISTANCE,CBO可能放弃分区裁剪,改走全局向量索引扫描。
典型表现:
- 执行计划出现
VECTOR INDEX RANGE SCAN但Partition Start/Stop是ALL -
A-Rows远大于预期,Buffers飙升到百万级
临时规避方法:
- 拆成两步:先用传统条件过滤出目标分区,再在结果集上做向量计算
- 显式指定分区:
SELECT /*+ PARTITION(p_202506) */ ... FROM t PARTITION (p_202506) - 检查向量索引类型——IVF比HNSW更容易与分区协同,HNSW在23ai中默认不感知分区边界
真正麻烦的点不在操作本身,而在“查完才意识到分区没裁剪”——因为执行计划里那行PARTITION RANGE太不起眼,容易被NESTED LOOPS或HASH JOIN的缩进遮住。盯住Id列最左边的数字,从0开始逐行往下捋,才是唯一靠谱的办法。











