Oracle 19c分区表查询不走索引,八成是索引状态异常(如UNUSABLE)或统计信息过期;需先查USER_INDEXES中STATUS是否为VALID,再用DBMS_STATS.GATHER_TABLE_STATS强制刷新统计信息并设force=>TRUE绕过锁表。
oracle 19c 分区表查询不走索引,八成是统计信息过期或索引状态异常,而不是分区本身的问题。
查索引是否可用(STATUS = VALID?)
分区表的索引可能被标记为 UNUSABLE,尤其在批量导入、ALTER TABLE ... EXCHANGE PARTITION 或重建失败后。一旦不可用,优化器直接跳过它,连评估都不做。
- 执行
SELECT INDEX_NAME, STATUS, PARTITIONED FROM USER_INDEXES WHERE TABLE_NAME = 'T_LOCRECORD',重点看STATUS列是否为VALID - 若为
UNUSABLE,直接重建:ALTER INDEX idx_device_time REBUILD(注意:加ONLINE可避免 DML 阻塞) - 如果是局部索引(
PARTITIONED = YES),需确认对应分区索引是否也VALID;可用SELECT INDEX_NAME, PARTITION_NAME, STATUS FROM USER_IND_PARTITIONS WHERE INDEX_NAME = 'IDX_DEVICE_TIME'查
验证统计信息是否准确(GATHER_TABLE_STATS 是关键)
Oracle 19c 默认启用自动统计信息收集,但实际中常因锁表、权限不足或手动禁用而失效。过时的统计信息会让 CBO 错误估算“走索引成本高”,转而选全表扫描——哪怕只查 1% 的数据。
- 先查最新统计时间:
SELECT LAST_ANALYZED, NUM_ROWS, SAMPLE_SIZE FROM USER_TABLES WHERE TABLE_NAME = 'T_LOCRECORD' - 若
LAST_ANALYZED是几个月前,或NUM_ROWS明显偏离实际(比如SELECT COUNT(*) FROM T_LOCRECORD差几倍),说明已过期 - 强制刷新:
EXEC DBMS_STATS.GATHER_TABLE_STATS(ownname => 'YOUR_SCHEMA', tabname => 'T_LOCRECORD', estimate_percent => DBMS_STATS.AUTO_SAMPLE_SIZE, method_opt => 'FOR ALL COLUMNS SIZE AUTO', cascade => TRUE, force => TRUE) - 特别注意:
force => TRUE能绕过ORA-20005: object statistics are locked错误,但需确保无其他会话正依赖旧统计
执行计划里看到 PARTITION RANGE SINGLE 却走 TABLE ACCESS FULL?
这说明 Oracle 已定位到具体分区(比如 Pstart=24 / Pstop=24),但没用索引扫描,而是对该分区做了全表扫描。此时问题不在分区裁剪,而在该分区内索引是否有效或是否被选中。
- 检查谓词是否污染了索引列:比如
WHERE DEVICE_ID = 'xxx' AND TRUNC(GPSTIME) = DATE '2010-01-25'——TRUNC()会让GPSTIME上的普通索引失效 - 确认查询条件是否覆盖了索引前导列:若索引是
(DEVICE_ID, GPSTIME),但 SQL 只写了WHERE GPSTIME > ...,则无法使用该复合索引(除非触发 INDEX SKIP SCAN,但代价高且不总启用) - 观察
Predicate Information部分:如果出现filter("TL"."DEVICE_ID"='xxx' AND "TL"."GPSTIME",说明所有过滤都在访问路径之后做,即没下推到索引层——大概率是隐式转换或函数导致
真正容易被忽略的是:分区表上建的全局索引,其统计信息是独立于表和分区的,DBMS_STATS.GATHER_TABLE_STATS 不会自动更新它。必须单独对索引 gather:EXEC DBMS_STATS.GATHER_INDEX_STATS('YOUR_SCHEMA', 'IDX_DEVICE_TIME')。











