OR EXISTS语句的优化方法

OR EXISTS语句的优化方法:

这库一直很空闲,但无意中看了一下,发现其中很多语句都很有问题,都是典型的OR问题语句,如果并发量大的话,CPU一下子就飙高了。
OR语句一直是性能杀手,当存在一两个的时候一般可以用union和union all来优化,请看以下例子。

1.在原句中使用了or语句并且or语句里面使用exists语句,这样给优化器造成了很大的迷惑。
2.从执行计划看来,貌似没有什么问题。
3.但从统计数据来看,一致读非常高,达到了4百多万次。

select count(*)
  from UNIOMS0808.SETTLEMENT s
 where (settlementStatus = 3)
   and (companyCode like '%GDSPID01687%' or exists
        (select 1
           from UNIOMS0808.PROVIDER pro
          where s.companyCode = pro.cpId
            and pro.companyId in
                (select com.companyId
                   from UNIOMS0808.COMPANY com
                  where com.companyCode like '%GDSPID01687%')));

Execution Plan
----------------------------------------------------------
   0      SELECT STATEMENT ptimizer=CHOOSE (Cost=164 Card=1 Bytes=14)
   1    0   SORT (AGGREGATE)
   2    1     FILTER
   3    2       TABLE ACCESS (FULL) OF 'SETTLEMENT' (Cost=164 Card=1939 Bytes=27146)
   4    2       NESTED LOOPS (Cost=375 Card=190 Bytes=6840)
   5    4         TABLE ACCESS (FULL) OF 'PROVIDER' (Cost=20 Card=355 Bytes=4615)
   6    4         TABLE ACCESS (BY INDEX ROWID) OF 'COMPANY' (Cost=1 Card=1 Bytes=23)
   7    6           INDEX (UNIQUE SCAN) OF 'PK_COMPANY' (UNIQUE)

Statistics
----------------------------------------------------------
          0  recursive calls
          0  db block gets
    4726442  consistent gets
          0  physical reads
          0  redo size
        406  bytes sent via SQL*Net to client
        503  bytes received via SQL*Net from client
          2  SQL*Net roundtrips to/from client
          0  sorts (memory)
          0  sorts (disk)
          1  rows processed

优化思路:直接将or语句转换为union语句观察一下。

select count(1)
from 
(
select SETTLEMENTID
  from UNIOMS0808.SETTLEMENT s
 where (settlementStatus = 3)
   and (companyCode like '%GDSPID01687%')
union
select SETTLEMENTID
  from UNIOMS0808.SETTLEMENT s
 where (settlementStatus = 3)
   and exists(select 1
           from UNIOMS0808.PROVIDER pro, UNIOMS0808.COMPANY com
          where s.companyCode = pro.cpId
            and pro.companyId =com.companyId
            and com.companyCode like '%GDSPID01687%')
);

Execution Plan
----------------------------------------------------------
   0      SELECT STATEMENT ptimizer=CHOOSE (Cost=376 Card=1)
   1    0   SORT (AGGREGATE)
   2    1     VIEW (Cost=376 Card=1199)
   3    2       SORT (UNIQUE) (Cost=376 Card=1199 Bytes=37355)
   4    3         UNION-ALL
   5    4           TABLE ACCESS (FULL) OF 'SETTLEMENT' (Cost=164 Card=994 Bytes=24850)
   6    4           HASH JOIN (Cost=199 Card=205 Bytes=12505)
   7    6             NESTED LOOPS (Cost=34 Card=14 Bytes=504)
   8    7               TABLE ACCESS (FULL) OF 'PROVIDER' (Cost=20 Card=14 Bytes=182)
   9    7               TABLE ACCESS (BY INDEX ROWID) OF 'COMPANY' (Cost=1 Card=1 Bytes=23)
  10    9                 INDEX (UNIQUE SCAN) OF 'PK_COMPANY' (UNIQUE)
  11    6             TABLE ACCESS (FULL) OF 'SETTLEMENT' (Cost=164 Card=19884 Bytes=497100)

Statistics
----------------------------------------------------------
          0  recursive calls
          0  db block gets
       1917  consistent gets
          0  physical reads
          0  redo size
        406  bytes sent via SQL*Net to client
        503  bytes received via SQL*Net from client
          2  SQL*Net roundtrips to/from client
          1  sorts (memory)
          0  sorts (disk)
          1  rows processed

观察效果:效果非常明显,一致读下降到2千个,是原来的千分之0.4。从执行计划中看最大不同在于新的执行计划使用了hash join,而且显示的cost比原来的还要大。
问题分析:由于or exists语句导致优化器选择了nested loops进行表连接,而nested loops对于少数据量处理是很好的,但对于全表扫描来说则效率更低,最终导致大量的一致读产生。
有兴趣的可以进一步使用10046事件进行分析,确定问题的症结。

以下提供可重现的测试方法

create table test as select * from dba_objects;
create table test1 as select * from dba_objects;

优化前
select count(*)
  from test s
 where (OBJECT_TYPE = 'VIEW')
   and (OBJECT_NAME like '%DBA_TABLES%' or exists
        (select 1
           from test1 pro
          where s.object_id = pro.object_id
            and pro.OBJECT_NAME = 'DBA_TABLES'));
            
优化后
select count(1)
from 
(
select object_id
  from test s
 where (OBJECT_TYPE = 'VIEW')
   and (OBJECT_NAME like '%DBA_TABLES%')
UNION   
select object_id
  from test s
 where (OBJECT_TYPE = 'VIEW')
   and exists
        (select 1
           from test1 pro
          where s.object_id = pro.object_id
            and pro.OBJECT_NAME = 'DBA_TABLES')
);            

来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/13605188/viewspace-706829/,如需转载,请注明出处,否则将追究法律责任。

转载于:http://blog.itpub.net/13605188/viewspace-706829/

飞塔防火墙之Link Monitor Link Monitor类似于SLA,飞塔防火墙线路质量探测的一个功能。 阅读详情

相关推荐

【SQL语句优化

【SQL语句优化

学无止境 483

in、orexists区别

in 和or区别: 如果in和or所在列有索引或者主键的话,or和in没啥差别,执行计划和执行时间都几乎一样。 如果in和or所在列没有 索引的话,性能差别就很大了。在没有索引的情况下,随着in或者or后面的数据量越多,in的效率不会有太大的下降,但是or会随着记录越多的话性能下降 非常厉害  因此在给in和or的效率下定义的时候,应该再加上一个条件,就是所在的列是否有索引或

xinSmile的博客 4955

2018武汉市建筑轮廓GIS数据

2018武汉市建筑轮廓GIS数据

MySQL关键字OR/IN/NOT IN/EXISTS/NOT EXISTS的区别

IN 和 OR 的区别: 如果in和or所在列有索引或者主键的话,or和in没啥差别,执行计划和执行时间都几乎一样。 如果in和or所在列没有 索引的话,性能差别就很大了。在没有索引的情况下,随着in或者or后面的数据量越多,in的效率不会有太大的下降,但是or会随着记录越多的话性能下降 非常厉害。 因此在给in和or的效率下定义的时候,应该再加上一个条件,就是所在的列是否有索引或者是否是主键。如果有索引或者主键性能没啥差别,如果没有索引,性能差别不是一点点! IN 和 EXISTS 的区别: EXISTS

不积跬步无以至千里 2169

oracle数据库or exists,Oracle Not Exists运算符

本篇文章帮大家学习Oracle Not Exists运算符,包含了Oracle Not Exists运算符使用方法、操作技巧、实例演示和注意事项,有一定的学习价值,大家可以用来参考。在本教程中,您将学习如何使用Oracle NOT EXISTS运算符从一个数据中减去另一组数据集。Oracle NOT EXISTS运算符简介NOT EXISTS运算符与EXISTS运算符相反。我们经常在子查询中使用N...

weixin_31262911的博客 1448

关于分析并优化同时存在or和exises运算符的mysql语句的讨论

前言:sql优化是个老生常谈的话题。个人理解的话,优化主要是对查询的优化。 在业务逻辑中,遇到一个有意思的sql语句 ,同时使用existsor运算后,效率的确慢好几百拍。 select `id` from `students` where `school_id` = '1' and (exists (select 1 from `school_tag` as `tag` where...

大唐锦绣的博客 1516

mysql中exists的用法详解

前言 在日常开发中,用mysql进行查询的时候,有一个比较少见的关键词exists,我们今天来学习了解一下这个 exists这个sql关键词的用法,这样在工作中遇到一些特定的业务场景就可以有更加多样化的解决方案 语法解释 语法 SELECT column1 FROM t1 WHERE [conditions] and EXISTS (SELECT * FROM t2 ); 说明 括号中的子查询并不会返回具体的查询到的数据,只是会返回true或者false,如果外层sql的字段在子查询中存在则返回true,

技术人集结地 5万+

Oracle sql语句简单优化

1、优化sql时,经常碰到使用in的语句,一定要用exists把它给换掉,因为Oracle在处理In时是按Or的方式做的,即使使用了索引也会很慢。比如:SELECT col1,col2,col3 FROM table1 a WHERE a.col1 not in (SELECT col1 FROM table2) 可替换为:SELECT col1,col2,col3 FROM table1 a WHERE not exists (SELECT 'x' FROM table2 b WHERE a.c

cymyell的专栏 508

sql优化in语句

在很多时候我们在sql中会用到in语句,in语句会使得sql查询不使用索引,这也大大减低了sql执行的效率,为了能够让sql在查询中使用索引,有很多种方式可以优化,比如如果in中的类型是确定值,那么可以用 字段=确定值 多个条件直接用or连接,这样也可以优化这个条件,还有就是对于in后面是一个子查询,可用通过right join或者left join 来实现优化,有时候可以通过把那个查询用 exi

lilovfly的专栏 1万+

25 union代替or --优化主题系列

当SQL语句or条件上面有一个为子查询 这个时候就可以用union代替or或者你发现执行计划中的filter有or 并且or后面跟上子查询EXISTS(select...)的时候就要注意 比如: 当然了 当你看到operation中的filter也应该要注意这些 看到filter后有orexists(select xx)  则改成union   示例如下(请自己动手实验):

leo0805的博客 577

MySQL--SQL语句优化--大全

本文介绍MySQL的一些常见的语句优化

IT利刃出鞘的博客 2452

SQL Tuning---各种语句的不同写法(收藏)

作者: fuyuncat来源: www.HelloDBA.com         最近处理的问题涉及SQL Tuning的东西比较多。不少语句不是加几个索引这么简单,而是语句是在太复杂了,有些作者都不知道是谁,逻辑非常难理解。碰到这种情况着实令人头疼。但是根据经验,很多语句的书写方式是可以用其他方式代替,通过尝试修改语句的写法,往往取得不错的效果。         

437

oracle or使用速度快马_Oracle sql 如何 更快 查询

1、SELECT子句中避免使用 " * ":ORACLE在解析的过程中, 会将"*" 依次转换成所有的列名, 这个工作是通过查询数据字典完成的, 这意味着将耗费更多的时间。2、sql语句用大写的:因为oracle总是先解析sql语句,把小写的字母转换成大写的再执行。3、WHERE子句中的连接顺序:ORACLE采用自下而上的顺序解析WHERE子句,根据这个原理,表之间的连接必须写在其他WHERE条件...

weixin_39846186的博客 230

MySQL必会的SQL查询语句优化方法你竟然还不知道!

前言 查询语句优化是SQL效率优化的一个方式,可以通过优化sql语句来尽量使用已有的索引,避免全表扫描,从而提高查询效率。最近在对项目中的一些sql进行优化,总结整理了一些方法。 1、尽量避免在 where 子句中对字段进行 null 值判断 应尽量避免在 where 子句中对字段进行 null 值判断,否则将导致引擎放弃使用索引而进行全表扫描。 如: select id from t where num is null 可以在num上设置默认值0,确保表中num列没有null值,然

SQY0809的博客 317

SQL中 EXISTS 的用法简介

EXISTS 作用是判断某个对象是否存在,常用于判断表或在WHERE子句等条件中使用,分别介绍如下: 1,可以判断某个表或某对象是否存在 if exists(select * from sys.tables where name = 'xTable') print '表 xTable 存在' else print '表 xTable 不存在' go 2, exists 在WHERE子

shenzhenNBA的专栏 3506

SQL中关于 EXISTS关键字的使用

SQL中关于 EXISTS关键字的使用

胡大可的博客 1864

MP条件构造器之常用功能详解(or、and、exists、notExists

方法是 MyBatis-Plus 中用于构建查询条件的高级方法之一,它用于在查询中添加一个 NOT EXISTS 子查询。方法是 MyBatis-Plus 中用于构建查询条件的高级方法之一,它用于在查询中添加一个 EXISTS 子查询。方法是 MyBatis-Plus 中用于构建查询条件的基本方法之一,它用于在查询条件中添加 AND 逻辑。方法是 MyBatis-Plus 中用于构建查询条件的基本方法之一,它用于在查询条件中添加 OR 逻辑。现在,我们希望根据动态条件来决定是否使用 OR 连接查询条件。

2301_80093566的博客 2717

in和=、existsor区别

in和or :如果in和or所在列有索引或者主键的话,or和in没啥差别。如果in和or所在列没有索引的话,随着in或者or后面的数据量越多,in的效率不会有太大的下降,但是or会随着记录越多的话性能下降非常厉害. SELECT * FROM test WHERE id IN (1,23,48); SELECT * FROM test WHERE id =1 OR id=23 OR id=48 i...

he_jiabeihe的博客 1566

PostgreSQL对or exists产生的filter优化

PostgreSQL会对or exists产生的filter进行优化,上一篇文章没有测试exists中有大表的情况,今天来测试一下exists中有大表的情况 注意:测试期间没有对表添加索引 create table a as select * from dba_objects; create table b as select * from a; create table c as select * from a; create table d as select * from a; insert i

落落的专栏 专注SQL调优 性能调优 1214

MSSQL语句的性能调试(一)使用OR还是Exists

在写SQL语句的时候,经常会使用OR语句OR语句的性能不是很好,经常让表的索引失去作用。 最近调试一个语句,里面有一个搜索条件是A=1 or B=1 or C=1。 其中的A、B、C是同一个表里面的字段名。因为使用了OR语句,结果语句的性能不是很快。 原来的语句: SELECT * FROM Users Where isActive=1 AND (A=1 OR B=1 OR C=

dogfish的专栏 2027

oracle中的exists 和not exists 用法详解

有两个简单例子,以说明 “exists”和“in”的效率问题 1) select * from T1 where exists(select 1 from T2 where T1.a=T2.a) ;     T1数据量小而T2数据量非常大时,T1 2) select * from T1 where T1.a in (select T2.a from T2) ;      T

jack_one的专栏 815
上一篇: 索引空间三倍于表大小
下一篇: 函数索引的问题一则
cuanye4002
博客等级 码龄10年 0粉丝 0原创
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值