awr中“sql ordered by physical reads (unoptimized)”列表直接暴露未走smart scan的sql,其值越高说明smart scan失效越严重;常见原因包括函数导致谓词无法下推、hcc压缩下storage index失效、执行计划中io_cell_offload_eligible_bytes与returned_bytes差距小等。
看 awr 里 “sql ordered by physical reads (unoptimized)”
这个列表直接暴露哪些 sql 没走 smart scan。它统计的是“未优化读请求”(unoptimized read requests),也就是绕过存储节点过滤、把原始数据块全拉到 db 节点再处理的 i/o。数值越高,说明 smart scan 失效越严重。
常见诱因包括:
-
NVL、TO_CHAR、UPPER等函数出现在 WHERE 条件中,导致谓词无法下推 - 查询用了
/*+ NO_OFFLOAD */或被Quarantine标记过 - 表是 HCC
QUERY HIGH压缩,但列数据分布太均匀,Storage Index 失效 - 执行计划显示
FULL TABLE SCAN,但IO_CELL_OFFLOAD_ELIGIBLE_BYTES和IO_CELL_OFFLOAD_RETURNED_BYTES差距极小
查 v$sql 中 offload_pct 计算公式是否准确
别只信 AWR 报告里那个“Smart Scan %”的汇总值——它可能掩盖单条 SQL 的真实表现。用下面这个查询手动算每条 SQL 的 offload 率,更准:
SELECT sql_id, io_cell_offload_eligible_bytes / 1024/1024/1024 eligible_gb, io_cell_offload_returned_bytes / 1024/1024/1024 returned_gb, ROUND((1 - io_cell_offload_returned_bytes / NULLIF(io_cell_offload_eligible_bytes, 0)) * 100, 1) offload_pct FROM v$sql WHERE sql_text LIKE '%orders%' AND executions > 10;
注意点:
- 分母为 0 时要
NULLIF,否则整条记录被过滤掉,漏掉问题 SQL - 如果
offload_pct长期低于 60%,优先检查 Storage Index 是否生效(见下一条) - 同一 SQL_ID 多次执行后
eligible_gb累积变大,但returned_gb没跟上,说明过滤逻辑没起作用
验证 Storage Index 实际节省了多少物理读
Storage Index 是 Smart Scan 能否高效的关键杠杆,但它不显式建索引,也不在 dba_indexes 里。它的效果体现在存储节点的物理读节省上:
SELECT cell_name, physical_read_bytes / 1024/1024/1024 read_gb, io_saved_by_storage_index / 1024/1024/1024 saved_gb, ROUND(io_saved_by_storage_index / NULLIF(physical_read_bytes, 0) * 100, 1) save_pct FROM v$cell_state;
如果 save_pct 持续低于 5%,基本可判定 Storage Index 形同虚设。典型原因有:
- 时间列(如
create_time)顺序插入,每个 1MB extent 时间跨度太小(比如仅 2 小时),而查询条件跨 7 天 → 几乎所有 extent 都命中,筛不掉数据 - 字段高基数且分布均匀(如 UUID、哈希值),min/max 范围重叠严重
- 表刚加载完或大量 DML 后未触发 Storage Index 重建(它只在扫描时动态维护)
留意 direct path read 是否真被 Smart Scan 利用
Smart Scan 只对使用 direct path read 的操作生效(如并行查询、大表全扫)。但不是所有 direct path read 都能触发 Smart Scan:
- 确认等待事件是
cell table smart scan或cell index smart scan,而不是direct path read—— 后者说明没下推 - 平均等待时间超过 2ms(比如 15ms+)就是异常信号,说明存储节点在做无效扫描或资源争用
- HCC
QUERY HIGH表上做SELECT COUNT(*),即使走 direct path,也可能因压缩格式限制无法下推谓词,只能 passthru
真正难判断的点在于:offload_pct 看似达标,但大部分收益来自 Storage Index 跳过 1MB 区间,而非谓词过滤;这种“伪高效”会掩盖 Bloom Filter 或列投影没生效的问题。得结合 v$cell_state 和单条 SQL 的 io_cell_offload_returned_bytes 交叉验证。











