WHY?

  • IN 和 NOT IN 是比较常用的关键字,为什么要尽量避免呢?

1、效率低

  • 项目中遇到这么个情况:
  • t1表 和 t2表  都是150w条数据,600M的样子,都不算大。
  • 但是这样一句查询 
    select * from t1 where phone not in (select phone from t2)
  • 直接就把我跑傻了。。。十几分钟,检查了一下  phone在两个表都建了索引,字段类型也是一样的。原来not in 是不能命中索引的。。。。
  • 改成 NOT EXISTS 之后查询 20s ,效率真的差好多。
    1.  
      select * from t1
    2.  
      where not EXISTS (select phone from t2 where t1.phone =t2.phone)
     

2、容易出现问题,或查询结果有误 (不能更严重的缺点)

  • 以 IN 为例。建两个表:test1 和 test2
    1.  
      create table test1 (id1 int)
    2.  
      create table test2 (id2 int)
    3.  
       
    4.  
      insert into test1 (id1) values (1),(2),(3)
    5.  
      insert into test2 (id2) values (1),(2)
     
  • 我想要查询,在test2中存在的  test1中的id 。使用IN的一般写法是:
    1.  
      select id1 from test1
    2.  
      where id1 in (select id2 from test2)
 
  • 结果是: OK 木有问题!
  • 但是如果我一时手滑,写成了:
    1.  
      select id1 from test1
    2.  
      where id1 in (select id1 from test2)
 
  • 不小心把id2写成id1了 ,会怎么样呢?
  • 结果是: EXCUSE ME! 为什么不报错? 
    1.  
      单独查询 select id1 from test2 是一定会报错: 消息 207,级别 16,状态 1,第 11 行 列名 'id1' 无效。
    2.  
      然而使用了IN的子查询就是这么敷衍,直接查出 1 2 3
  • 这仅仅是容易出错的情况,自己不写错还没啥事儿,下面来看一下 NOT IN 直接查出错误结果的情况:
  • 给test2插入一个空值:
     
insert into test2 (id2) values (NULL)
  • 我想要查询,在test2中不存在的  test1中的id 。
    1.  
      select id1 from test1
    2.  
      where id1 not in (select id2 from test2)
  • 结果是:空白! 显然这个结果不是我们想要的。我们想要3。为什么会这样呢?
  • 原因是:NULL不等于任何非空的值啊!如果id2只有1和2, 那么3<>1 且 3<>2 所以3输出了,但是 id2包含空值,那么 3也不等于NULL 所以它不会输出。

  1. (跑题一句:建表的时候最好不要允许含空值,否则问题多多。)
 

HOW?

1、用 EXISTS 或 NOT EXISTS 代替

  1.  
    select * from test1
  2.  
    where EXISTS (select * from test2 where id2 = id1 )
  3.  
    select * FROM test1
  4.  
    where NOT EXISTS (select * from test2 where id2 = id1 )

2、用JOIN 代替

  1.  
    select id1 from test1
  2.  
    INNER JOIN test2 ON id2 = id1
  3.  
    select id1 from test1
  4.  
    LEFT JOIN test2 ON id2 = id1
  5.  
    where id2 IS NULL

妥妥的没有问题了!

  • PS:那我们死活都不能用 IN 和 NOT IN 了么?并没有,一位大神曾经说过,如果是确定且有限的集合时,可以使用。如 IN (0,1,2)。

SQL优化 - 避免使用 IN 和 NOT IN的更多相关文章

  1. SQL优化案例—— RowNumber分页

    将业务语句翻译成SQL语句不仅是一门技术,还是一门艺术. 下面拿我们程序开发工程师最常用的ROW_NUMBER()分页作为一个典型案例来说明. 先来看看我们最常见的分页的样子: WITH CTE AS ...

  2. sql 优化

    1.选择最有效率的表名顺序(只在基于规则的优化器中有效): oracle的解析器按照从右到左的顺序处理 from 子句中的表名,from子句中写在最后的表(基础表driving table)将被最先处 ...

  3. SQL 优化总结

    SQL 优化总结 (一)SQL Server 关键的内置表.视图 1. sysobjects         SELECT name as '函数名称',xtype as XType  FROM  s ...

  4. (转)SQL 优化原则

    一.问题的提出 在应用系统开发初期,由于开发数据库数据比较少,对于查询SQL语句,复杂视图的的编写等体会不出SQL语句各种写法的性能优劣,但是如果将应用 系统提交实际应用后,随着数据库中数据的增加,系 ...

  5. sql优化阶段性总结以及反思

    Sql优化思路阶段性心得: 这段时间的优化做了好几个案例,其实有很多的类似点,都是好几张大表的相互连接,然后执行长达好几个小时,甚至都跑不出来. 自己差不多的思路就是Parallel full tab ...

  6. mysql sql优化实例

    mysql sql优化实例 优化前: pt-query-degist分析结果: # Query 3: 0.00 QPS, 0.00x concurrency, ID 0xDC6E62FA021C85B ...

  7. SQL优化技巧

    我们开发的大部分软件,其基本业务流程都是:采集数据→将数据存储到数据库中→根据业务需求查询相应数据→对数据进行处理→传给前台展示.对整个流程进行分析,可以发现软件大部分的操作时间消耗都花在了数据库相关 ...

  8. ORACLE常用SQL优化hint语句

    在SQL语句优化过程中,我们经常会用到hint,现总结一下在SQL优化过程中常见Oracle HINT的用法: 1. /*+ALL_ROWS*/ 表明对语句块选择基于开销的优化方法,并获得最佳吞吐量, ...

  9. SQL优化有偿服务

    本人目前经营MySQL数据库的SQL优化服务,100块钱一条.具体操作模式 其中第一条,可以通过在微信朋友圈转发链接中的信息(http://www.yougemysqldba.com/discuz/v ...

  10. 【MySQL】SQL优化系列之 in与range 查询

    首先我们来说下in()这种方式的查询 在<高性能MySQL>里面提及用in这种方式可以有效的替代一定的range查询,提升查询效率,因为在一条索引里面,range字段后面的部分是不生效的. ...

随机推荐

  1. 第一天课程:第一个python程序print say hello

    print("Hello World") linux下要加可执行权限 chmod 755 hello.py 权限755,7=4+2+1,4是读,2是写,1是执行,第一个7代表用户, ...

  2. typescript接口的概念 以及属性类型接口

    /* 1.vscode配置自动编译 1.第一步 tsc --inti 生成tsconfig.json 改 "outDir": "./js", 2.第二步 任务 ...

  3. 02-创建String对象

    创建一个String对象实在是太简单了,就是因为简单,所以有很多java程序员做了好几年的开发,也没有注意这些小细节问题 String字符串的本质就是char数据对象, 那么char[0]数组当中的一 ...

  4. Android Studio设置自定义字体

    Android Studio设置自定义字体 (1)进入设置页面,File->Settings (2)自定义字体Editor->Colors&Fonts->Font (3)点击 ...

  5. Elasticsearch的JavaAPI

    获取客户端对象 public class App { private TransportClient client; //获取客户端对象 @Before public void getClinet() ...

  6. tp3.2 支付宝app支付

    pay方法 /** *支付宝支付 */ public function pay($param) { vendor('alipay.AopSdk');// 加载类库 $config = array( ' ...

  7. 【LeetCode】2. Add Two Numbers 两数相加

    给出两个 非空 的链表用来表示两个非负的整数.其中,它们各自的位数是按照 逆序 的方式存储的,并且它们的每个节点只能存储 一位 数字. 如果,我们将这两个数相加起来,则会返回一个新的链表来表示它们的和 ...

  8. json.loads()的字符串中为单引号引发的错误

    如下错误属于弱智错误,但是错的原因让我无语,所以记录一下 str2="{'card':6217001650004184441}"print(json.loads(str2)) Tr ...

  9. Mybatis实现in查询(注解形式和xml形式)

    1. @Select注解中使用in @Select({"<script> " + " select * "+ " from busines ...

  10. embsysregview 0.26 无法安装的解决方法。

    最近看到一个比较好的 eclipse 插件:embsysregview,于是想装起来用用看.结果安装过程出错,4个 jar 的包下载不下来,并且通过本地安装的方法也不行. 后来终于找到作者的回复,作者 ...