Oracle 执行计划中的 ACCESS 和 FILTER 详解
Oracle 执行计划中的 ACCESS 和 FILTER 详解
在 Oracle 执行计划中,ACCESS 和 FILTER 是两个关键的操作类型,它们描述了 Oracle 如何检索和处理数据。理解这两个概念对于 SQL 性能调优至关重要。
ACCESS(访问)
ACCESS 表示 Oracle 通过索引或直接访问表的方式来获取数据。
特点
- 索引访问:通常通过索引快速定位数据
- 高效检索:直接访问所需数据块,减少I/O
- 访问路径:包括索引唯一扫描(INDEX UNIQUE SCAN)、索引范围扫描(INDEX RANGE SCAN)等
常见 ACCESS 操作类型
| 操作类型 | 描述 | 示例 | 
|---|---|---|
| INDEX UNIQUE SCAN | 通过唯一索引查找单行 | 主键查找 | 
| INDEX RANGE SCAN | 通过索引查找多行 | WHERE id BETWEEN 100 AND 200 | 
| INDEX FULL SCAN | 全索引扫描 | 需要索引列但无过滤条件 | 
| INDEX FAST FULL SCAN | 快速全索引扫描 | 类似全表扫描但只读索引 | 
| TABLE ACCESS FULL | 全表扫描 | 无合适索引时 | 
| TABLE ACCESS BY INDEX ROWID | 通过索引ROWID访问表 | 索引覆盖不全时 | 
ACCESS 示例
-- 索引唯一扫描示例
EXPLAIN PLAN FOR
SELECT * FROM employees WHERE employee_id = 100;-- 执行计划中会出现:
-- | Id | Operation                   | Name          |
-- |----|-----------------------------|---------------|
-- |  0 | SELECT STATEMENT            |               |
-- |  1 |  TABLE ACCESS BY INDEX ROWID| EMPLOYEES     |
-- |  2 |   INDEX UNIQUE SCAN         | EMP_ID_PK     |
FILTER(过滤)
FILTER 表示 Oracle 对已获取的数据应用额外的过滤条件。
特点
- 后置过滤:在获取数据后应用条件
- 性能影响:可能导致处理更多数据
- 常见场景:无法使用索引的条件、函数条件等
常见 FILTER 操作场景
-  对索引列应用函数: WHERE UPPER(last_name) = 'SMITH'
-  使用不等于(!=或<>)操作: WHERE department_id != 10
-  使用OR条件: WHERE department_id = 10 OR salary > 5000
-  使用LIKE以通配符开头: WHERE last_name LIKE '%SMITH%'
FILTER 示例
-- 过滤条件示例
EXPLAIN PLAN FOR
SELECT * FROM employees WHERE salary > 5000 AND UPPER(last_name) = 'SMITH';-- 执行计划中可能出现:
-- | Id | Operation         | Name      |
-- |----|-------------------|-----------|
-- |  0 | SELECT STATEMENT  |           |
-- |* 1 |  TABLE ACCESS FULL| EMPLOYEES |
--
-- Predicate Information:
-- 1 - filter("SALARY">5000 AND UPPER("LAST_NAME")='SMITH')
ACCESS 与 FILTER 对比
| 特性 | ACCESS | FILTER | 
|---|---|---|
| 执行时机 | 数据获取阶段 | 数据获取后 | 
| 效率 | 通常高效 | 可能低效 | 
| 索引使用 | 通常使用索引 | 通常不使用索引 | 
| 优化目标 | 尽可能多使用 | 尽可能减少 | 
| 典型操作 | 索引扫描 | 条件过滤 | 
性能优化建议
-  将FILTER转为ACCESS: - 为常用查询条件创建合适索引
- 重写SQL避免对索引列使用函数
 
-  复合索引策略: -- 创建复合索引支持多列查询 CREATE INDEX emp_name_salary_idx ON employees(last_name, salary);
-  避免全表扫描: - 确保查询能使用索引
- 使用INDEX提示强制使用索引
 
-  函数索引: -- 为函数条件创建函数索引 CREATE INDEX emp_upper_name_idx ON employees(UPPER(last_name));
-  统计信息更新: -- 确保统计信息准确 EXEC DBMS_STATS.GATHER_TABLE_STATS('HR', 'EMPLOYEES');
实际案例分析
案例1:将FILTER转为ACCESS
问题SQL:
SELECT * FROM orders WHERE TO_CHAR(order_date, 'YYYY-MM') = '2023-01';
执行计划:
TABLE ACCESS FULL ORDERSFILTER: TO_CHAR(order_date, 'YYYY-MM') = '2023-01'
优化方案:
-- 方案1: 使用范围查询
SELECT * FROM orders 
WHERE order_date >= TO_DATE('2023-01-01', 'YYYY-MM-DD')
AND order_date < TO_DATE('2023-02-01', 'YYYY-MM-DD');-- 方案2: 创建函数索引
CREATE INDEX orders_ym_idx ON orders(TO_CHAR(order_date, 'YYYY-MM'));
案例2:复合索引优化
问题SQL:
SELECT * FROM employees 
WHERE department_id = 10 
AND salary > 5000;
执行计划:
TABLE ACCESS FULL EMPLOYEESFILTER: department_id = 10 AND salary > 5000
优化方案:
-- 创建复合索引
CREATE INDEX emp_dept_sal_idx ON employees(department_id, salary);
优化后执行计划将显示使用索引范围扫描(INDEX RANGE SCAN)。
总结
- ACCESS表示数据检索方式,- FILTER表示数据获取后的过滤
- 优化目标是将尽可能多的 FILTER条件转为ACCESS条件
- 通过创建合适索引、重写SQL语句可以减少FILTER操作
- 使用执行计划工具定期检查SQL性能,识别不必要的FILTER操作
