【SQL优化】B树索引位图转换及OR到UNION(ALL)的改写
2015-10-11 09:34
585 查看
在11g中,or操作符如果发生在索引列上,数据库则会启用BITMAP CONVERSION(B树索引位图转换),如:
SQL> select * from emp where empno=7788 or ename='SCOTT';
执行计划
----------------------------------------------------------
Plan hash value: 1272340143
--------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
--------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 2 | 78 | 3 (0)| 00:00:01 |
| 1 | TABLE ACCESS BY INDEX ROWID | EMP | 2 | 78 | 3 (0)| 00:00:01 |
| 2 | BITMAP CONVERSION TO ROWIDS | | | | | |
| 3 | BITMAP OR | | | | | |
| 4 | BITMAP CONVERSION FROM ROWIDS| | | | | |
|* 5 | INDEX RANGE SCAN | PK_EMP | | | 0 (0)| 00:00:01 |
| 6 | BITMAP CONVERSION FROM ROWIDS| | | | | |
|* 7 | INDEX RANGE SCAN | IDX_EMP_ENAME | | | 1 (0)| 00:00:01 |
--------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
5 - access("EMPNO"=7788)
7 - access("ENAME"='SCOTT')
统计信息
----------------------------------------------------------
1 recursive calls
0 db block gets
3 consistent gets
0 physical reads
0 redo size
868 bytes sent via SQL*Net to client
415 bytes received via SQL*Net from client
2 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
1 rows processed
两个索引,分别转化为位图,满足各自条件的设置位为1,如果两个索引的位都为1,则rowid保留,然后再根据rowid去回表提取记录。
我们可以改写为union:
SQL> select * from emp where empno=7788
2 union
3 select * from emp where ename='SCOTT';
执行计划
----------------------------------------------------------
Plan hash value: 4119156321
-----------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-----------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 2 | 78 | 5 (80)| 00:00:01 |
| 1 | SORT UNIQUE | | 2 | 78 | 5 (80)| 00:00:01 |
| 2 | UNION-ALL | | | | | |
| 3 | TABLE ACCESS BY INDEX ROWID| EMP | 1 | 39 | 1 (0)| 00:00:01 |
|* 4 | INDEX UNIQUE SCAN | PK_EMP | 1 | | 0 (0)| 00:00:01 |
| 5 | TABLE ACCESS BY INDEX ROWID| EMP | 1 | 39 | 2 (0)| 00:00:01 |
|* 6 | INDEX RANGE SCAN | IDX_EMP_ENAME | 1 | | 1 (0)| 00:00:01 |
-----------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
4 - access("EMPNO"=7788)
6 - access("ENAME"='SCOTT')
统计信息
----------------------------------------------------------
1 recursive calls
0 db block gets
4 consistent gets
0 physical reads
0 redo size
864 bytes sent via SQL*Net to client
415 bytes received via SQL*Net from client
2 SQL*Net roundtrips to/from client
1 sorts (memory)
0 sorts (disk)
1 rows processed
其实个人觉得,改写为union all然后再去重更好:
SQL> select distinct empno,ename from (
2 select empno,ename from emp where empno=7788
3 union all
4 select empno,ename from emp where ename='SCOTT');
执行计划
----------------------------------------------------------
Plan hash value: 707634659
------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 2 | 20 | 4 (25)| 00:00:01 |
| 1 | HASH UNIQUE | | 2 | 20 | 4 (25)| 00:00:01 |
| 2 | VIEW | | 2 | 20 | 3 (0)| 00:00:01 |
| 3 | UNION-ALL | | | | | |
| 4 | TABLE ACCESS BY INDEX ROWID| EMP | 1 | 10 | 1 (0)| 00:00:01 |
|* 5 | INDEX UNIQUE SCAN | PK_EMP | 1 | | 0 (0)| 00:00:01 |
| 6 | TABLE ACCESS BY INDEX ROWID| EMP | 1 | 10 | 2 (0)| 00:00:01 |
|* 7 | INDEX RANGE SCAN | IDX_EMP_ENAME | 1 | | 1 (0)| 00:00:01 |
------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
5 - access("EMPNO"=7788)
7 - access("ENAME"='SCOTT')
统计信息
----------------------------------------------------------
1 recursive calls
0 db block gets
4 consistent gets
0 physical reads
0 redo size
486 bytes sent via SQL*Net to client
415 bytes received via SQL*Net from client
2 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
1 rows processed
SQL>
这不,union all 再distinct的资源耗费最低。
以上试验方法来自《Oracle查询优化改写-技巧与案例》一书。
SQL> select * from emp where empno=7788 or ename='SCOTT';
执行计划
----------------------------------------------------------
Plan hash value: 1272340143
--------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
--------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 2 | 78 | 3 (0)| 00:00:01 |
| 1 | TABLE ACCESS BY INDEX ROWID | EMP | 2 | 78 | 3 (0)| 00:00:01 |
| 2 | BITMAP CONVERSION TO ROWIDS | | | | | |
| 3 | BITMAP OR | | | | | |
| 4 | BITMAP CONVERSION FROM ROWIDS| | | | | |
|* 5 | INDEX RANGE SCAN | PK_EMP | | | 0 (0)| 00:00:01 |
| 6 | BITMAP CONVERSION FROM ROWIDS| | | | | |
|* 7 | INDEX RANGE SCAN | IDX_EMP_ENAME | | | 1 (0)| 00:00:01 |
--------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
5 - access("EMPNO"=7788)
7 - access("ENAME"='SCOTT')
统计信息
----------------------------------------------------------
1 recursive calls
0 db block gets
3 consistent gets
0 physical reads
0 redo size
868 bytes sent via SQL*Net to client
415 bytes received via SQL*Net from client
2 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
1 rows processed
两个索引,分别转化为位图,满足各自条件的设置位为1,如果两个索引的位都为1,则rowid保留,然后再根据rowid去回表提取记录。
我们可以改写为union:
SQL> select * from emp where empno=7788
2 union
3 select * from emp where ename='SCOTT';
执行计划
----------------------------------------------------------
Plan hash value: 4119156321
-----------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-----------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 2 | 78 | 5 (80)| 00:00:01 |
| 1 | SORT UNIQUE | | 2 | 78 | 5 (80)| 00:00:01 |
| 2 | UNION-ALL | | | | | |
| 3 | TABLE ACCESS BY INDEX ROWID| EMP | 1 | 39 | 1 (0)| 00:00:01 |
|* 4 | INDEX UNIQUE SCAN | PK_EMP | 1 | | 0 (0)| 00:00:01 |
| 5 | TABLE ACCESS BY INDEX ROWID| EMP | 1 | 39 | 2 (0)| 00:00:01 |
|* 6 | INDEX RANGE SCAN | IDX_EMP_ENAME | 1 | | 1 (0)| 00:00:01 |
-----------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
4 - access("EMPNO"=7788)
6 - access("ENAME"='SCOTT')
统计信息
----------------------------------------------------------
1 recursive calls
0 db block gets
4 consistent gets
0 physical reads
0 redo size
864 bytes sent via SQL*Net to client
415 bytes received via SQL*Net from client
2 SQL*Net roundtrips to/from client
1 sorts (memory)
0 sorts (disk)
1 rows processed
其实个人觉得,改写为union all然后再去重更好:
SQL> select distinct empno,ename from (
2 select empno,ename from emp where empno=7788
3 union all
4 select empno,ename from emp where ename='SCOTT');
执行计划
----------------------------------------------------------
Plan hash value: 707634659
------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 2 | 20 | 4 (25)| 00:00:01 |
| 1 | HASH UNIQUE | | 2 | 20 | 4 (25)| 00:00:01 |
| 2 | VIEW | | 2 | 20 | 3 (0)| 00:00:01 |
| 3 | UNION-ALL | | | | | |
| 4 | TABLE ACCESS BY INDEX ROWID| EMP | 1 | 10 | 1 (0)| 00:00:01 |
|* 5 | INDEX UNIQUE SCAN | PK_EMP | 1 | | 0 (0)| 00:00:01 |
| 6 | TABLE ACCESS BY INDEX ROWID| EMP | 1 | 10 | 2 (0)| 00:00:01 |
|* 7 | INDEX RANGE SCAN | IDX_EMP_ENAME | 1 | | 1 (0)| 00:00:01 |
------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
5 - access("EMPNO"=7788)
7 - access("ENAME"='SCOTT')
统计信息
----------------------------------------------------------
1 recursive calls
0 db block gets
4 consistent gets
0 physical reads
0 redo size
486 bytes sent via SQL*Net to client
415 bytes received via SQL*Net from client
2 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
1 rows processed
SQL>
这不,union all 再distinct的资源耗费最低。
以上试验方法来自《Oracle查询优化改写-技巧与案例》一书。
相关文章推荐
- Oracle数据库命令大全
- [mysql]刷新windows恢复后mysql和"Access denied for user'root'@'IP'"处理问题
- oracle超级用户connection
- redis + Tomcat 8 的session共享解决
- 为什么不能用memcached存储Session
- txt文档内容入mysql
- 数据库日志管理
- Memcached 笔记与总结(6)PHP 实现 Memcached 的一致性哈希分布算法
- mysql增量备份
- 拆卸mysql
- 数据库 | SQL
- mac上的终端里添加mysql命令
- Mac OS X 10.11下如何安装MySQLdb?
- Oracle提高sql执行效率的心得建议
- 手动创建数据库的整体流程 Oracle 11g
- ORACLE同义词
- Hive安装 使用主机(win7)上的mysql数据库
- 数据库管理系统对SQL注入的影响
- 对比 Redis 与 Memcached
- Oracle EBS MRP 模块测试记录