oracle的optimizer会对一些sql语句进行查询转换,比如:

  1. 合并视图
  2. 子查询非嵌套化
  3. inlist转换

下面讲讲遇到的in list转化优化的案例:

create table test(
col1 varchar2(12)
col2 number
ext varchar2(4000)
); create index test_ind on test(user_id, col2);
create sequence seq_test cache 200;

第一步:准备一些测试数据(10个线程随机的插入数据):

#!/bin/sh
for((i=1;i<=$1;i++))
do
/home/oracle/insert.sh &
done
#######################################################
#!/bin/sh
. /home/oracle/.bash_profile
sqlplus -S /nolog<<EOF
conn test/ali88
declare
type arraylist is table of varchar2(20 byte);
arr_user arraylist;
ran number;
begin
arr_user := arraylist();arr_user.extend(3);arr_user(1):='xpchild001';
arr_user(2):='xpchild002';arr_user(3):='xpchild003';
ran :=dbms_random.value(1,3);
while(1>0) loop
insert into test(col1,col2,ext)values(arr_user(ran),seq_test.nextval,dbms_random.string('|', 300));
commit;
DBMS_LOCK.SLEEP(0.05);
end loop;
end;
/
EOF

下面看这个语句的执行计划:

  

delete from test t where col1 =:1 and col2 in
( :2 , :3 , :4 , :5 , :6 , :7 , :8 , :9 , :10 , :11 , :12 , :13 , :14 , :15 , :16 , :17 , :18 , :19 , :20 , :21); --------------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
--------------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 4 | 948 | 5 (0)| 00:00:01 |
| 1 | TABLE ACCESS BY INDEX ROWID| test | 4 | 948 | 5 (0)| 00:00:01 |
|* 2 | INDEX RANGE SCAN | test_ind | 4 | | 2 (0)| 00:00:01 |
--------------------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - access("col1"=:1)
filter("col2"=TO_NUMBER(:2) OR "col2"=TO_NUMBER(:3) OR
.........
"col2"=TO_NUMBER(:21))

分析:对于test_ind(col1,col2)这样的组合索引,oracle的优化器使用了access+filter的扫描方式,而对于热点表,或者col1存在大量记录的时候,
这样的扫描会从col1找到最小的col2,顺着leaf节点的链表,找到col2的最大值的区间里,进行filter,看下autotrace后的结果:

  

Statistics
----------------------------------------------------------
12389 consistent gets
20 rows

这里扫描了col1=:1前导列的所有leaf块,所以尽管只有20条记录,却有12389的逻辑读。

下面对这个sql进行inlist的查询转换:

  

ops$admin@orcl>alter session set optimizer_index_caching=100;

delete /*+ use_concat*/from test t where col1 =:1 and col2 in
( :2 , :3 , :4 , :5 , :6 , :7 , :8 , :9 , :10 , :11 , :12 , :13 , :14 , :15 , :16 , :17 , :18 , :19 , :20 , :21); ---------------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
---------------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 4 | 948 | 3 (0)| 00:00:01 |
| 1 | INLIST ITERATOR | | | | | |
| 2 | TABLE ACCESS BY INDEX ROWID| test | 4 | 948 | 3 (0)| 00:00:01 |
|* 3 | INDEX RANGE SCAN | test_ind | 4 | | 0 (0)| 00:00:01 |
---------------------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
3 - access("col1"=:1 AND ("col2"=TO_NUMBER(:2) OR "col2"=TO_NUMBER(:3) OR
"col2"=TO_NUMBER(:4) OR "col2"=TO_NUMBER(:5) OR "col2"=TO_NUMBER(:6) OR
......
/*+
BEGIN_OUTLINE_DATA
NUM_INDEX_KEYS(@"DEL$1" "T"@"DEL$1" "test_ind" 2)
INDEX(@"DEL$1" "T"@"DEL$1" ("test"."col1"
"test"."col2"))
OUTLINE_LEAF(@"DEL$1")
ALL_ROWS
OPT_PARAM('optimizer_index_caching' 100)
OPT_PARAM('_gby_hash_aggregation_enabled' 'false')
OPT_PARAM('_optim_peek_user_binds' 'false')
OPT_PARAM('_index_join_enabled' 'false')
OPT_PARAM('query_rewrite_enabled' 'false')
OPTIMIZER_FEATURES_ENABLE('10.2.0.4')
IGNORE_OPTIM_EMBEDDED_HINTS
END_OUTLINE_DATA
*/

注意:oracle的优化器会对in 列表的查询转换为or的查询,使用use_concat的hint提示,使oracle可以把or的操作转化为concatenate的union all操作。
但是这里如果想要转化为inlist的eterator操作,必须还要调整optimizer_index_caching,可以在system或者session级别,optimizer_index_caching的值的范围
是0到100,表示的是百分比,这个参数影响oracle优化器在选择index时的cost计算,这里设置成100,表示扫描过的root,branch节点块都cache在buffer里,所以每次
iterate从root到branch再到leaf节点时,oracle优化器认为cost会比较小,倾向于使用inlist iterator。

看一下autotrace后的结果:

Statistics
----------------------------------------------------------
81 consistent gets
20 rows

即每条记录平均三个逻辑读,从root->branch->leaf->table block。

  如果在生产环境中可以使用profile来固定上面的执行计划,这样不用更改任何的代码逻辑:

  

declare
v_hints sys.sqlprof_attr;
sql_fulltext clob;
begin
select SQL_FULLTEXT
into sql_fulltext
from v$sqlarea
where sql_id = 'xxxxxx';
v_hints := sys.sqlprof_attr('NUM_INDEX_KEYS(@"DEL$1" "T"@"DEL$1" "test_ind" 2)',
'INDEX(@"DEL$1" "T"@"DEL$1" ("test"."col1"',
'"test"."col2"))',
'OUTLINE_LEAF(@"DEL$1")',
'ALL_ROWS',
'OPT_PARAM(''optimizer_index_caching'' 100)');
dbms_sqltune.import_sql_profile(sql_fulltext,
v_hints,
'test',
force_match => true);
end;
/

  

oracle查询转换_inlist转换的更多相关文章

  1. Oracle中使用游标转换数据表中指定字段内容格式(拼音转数字)

    应用场景:将数据表TB_USER中字段NNDP的内容中为[sannanyinv]转换为[3男1女] 主要脚本:一个游标脚本+分割字符串函数+拼音转数字脚本 操作步骤如下: 1.创建类型 create ...

  2. ORACLE常用数值函数、转换函数、字符串函数介绍

    ORACLE常用数值函数.转换函数.字符串函数介绍. 数值函数: abs(m) m的绝对值 mod(m,n) m被n除后的余数 power(m,n) m的n次方 round(m[,n]) m四舍五入至 ...

  3. sql server 导出的datetime结果 CAST(0x00009E0E0095524F AS DateTime) 如何向mysql,oracle等数据库进行转换

    1. 处理 sql server 导出的 datetime 类型的字段 在进行sql server向mysql等其他数据进行迁移数据时,会发现使用sql server导出的datetime类型的结果是 ...

  4. hibernate查询部分字段转换成实体bean

    //hibernate查询部分字段转换成实体bean /** * 查询线路信息 */ @Override public List<Line> getSimpleLineListByTj(M ...

  5. 怎么将oracle的sql文件转换成mysql的sql文件

    怎么将sql文件导入PowerDesigner中的方法(将oracle的sql文件转换成mysql的sql文件)呢? 怎么将xx.sql文件的数据库结构导入powerdesigner 的方法呢? 现讲 ...

  6. LINQ查询表达式详解(2)——查询表达式的转换

    简介 C#在执行LINQ查询表达式的时候,并不会指定其执行语义,而是将查询表达式转换为遵循查询表达式模式的方法的调用.具体而言,查询表达式将转换为以下名称的调用:Where.Select.Select ...

  7. 45 个非常有用的 Oracle 查询语句

    ​ 这里我们介绍的是 40+ 个非常有用的 Oracle 查询语句,主要涵盖了日期操作,获取服务器信息,获取执行状态,计算数据库大小等等方面的查询.这些是所有 Oracle 开发者都必备的技能,所以快 ...

  8. 40多个非常有用的Oracle 查询语句

    给大家介绍是40多个非常有用的Oracle 查询语句,主要涵盖了日期操作,获取服务器信息,获取执行状态,计算数据库大小等等方面的查询.这些是所有Oracle 开发者都必备的技能,所以快快收藏吧! 日期 ...

  9. 45个非常有用的 Oracle 查询语句小结

    45个非常有用的 Oracle 查询语句小结 这里我们介绍的是 40+ 个非常有用的 Oracle 查询语句,主要涵盖了日期操作,获取服务器信息,获取执行状态,计算数据库大小等等方面的查询.这些是所有 ...

随机推荐

  1. works-er

  2. 添加samba用户,并设置密码

    5.3.3 添加samba用户,并设置密码; 我们用的方法是先添加用户,但添加的这些用户都是虚拟用户,因为这些用户是不能通过SHELL登录系统的;另外值得注意的是系统用户密码和Samba用户的密码是不 ...

  3. APP评价(星星点赞)很简单

    1.用代码或者storyboard创建5个button(现在一般都是5个星星) 我用的是storyboard 记得一定要设置button的tag值 在.h中 @property (weak, nona ...

  4. 搭建java开发环境

    windows 去Oracle官网下载exe文件,双击安装. 修改系统环境变量(我的电脑 -> 属性 -> 高级 -> 环境变量). JAVA_HOME: D:\Java\jdk1. ...

  5. websocket++简单使用例子

    前言 html5支持使用websocket协议与服务器保持一个长连接,方便双方互相传输数据,而且服务器也能主动发送信息给客户端,而在这之前使用HTTP是很难做到的.下面介绍使用C++实现的websoc ...

  6. (hdu)1042 N! 大数相乘

    题目链接:http://acm.split.hdu.edu.cn/showproblem.php?pid=1042 Problem Description Given an integer N( ≤ ...

  7. python 自动化之路 day 08 面向对象进阶

    面向对象高级语法部分 经典类vs新式类 静态方法.类方法.属性方法 类的特殊方法 反射 异常处理 面向对象高级语法部分 经典类vs新式类 把下面代码用python2 和python3都执行一下 1 2 ...

  8. 《JavaScript高级程序设计》笔记(3):传递参数

    待更新... 9.17更新: ECMAScript中所有函数的参数都是按值传递的.也就是说,把函数外部复制给函数内部的参数,就和把值从一个变量复制到另一个变量一样.基本类型值的传递如同基本类型变量的复 ...

  9. demo_07选择器练习

    <!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <title&g ...

  10. php中浮点数计算问题

    如果用php的+-*/计算浮点数的时候,可能会遇到一些计算结果错误的问题,比如echo intval( 0.58*100 );会打印57,而不是58,这个其实是计算机底层二进制无法精确表示浮点数的一个 ...