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动态绑定属性和方法

    基于Python 2.7.13测试. Python是动态语言,在类定义了之后,还可以动态地绑定属性和方法. 下面先来看怎么给类的实例动态地绑定属性和方法. >>> class Stu ...

  2. Anaconda的基本使用

  3. (转)Linux tcpdump命令详解

    简介 用简单的话来定义tcpdump,就是:dump the traffic on a network,根据使用者的定义对网络上的数据包进行截获的包分析工具. tcpdump可以将网络中传送的数据包的 ...

  4. 值得收藏的45个Python优质资源

    REST API:使用 Python,Flask,Flask-RESTful 和 Flask-SQLAlchemy 构建专业的 REST API https://www.udemy.com/rest- ...

  5. tomcat安全加固和规范

    tomcat是一个开源Web服务器,基于Tomcat的Web运行效率高,可以在一般的硬件平台上流畅运行,因此,颇受Web站长的青睐.不过,在默认配置下其存在一定的安全隐患,可被恶意攻击.以下是一些安全 ...

  6. virt-install详解

    man virt-install VIRT-INSTALL() Virtual Machine Manager VIRT-INSTALL() NAME virt-install - provision ...

  7. 理解Solr缓存及如何设置缓存大小

    文献地址:http://wangdg.com/understanding-and-tuning-solr-cache/ 理解Solr缓存及如何设置缓存大小 为了得到最好的检索性能,Solr会在内存中缓 ...

  8. shell脚本选择LOG里面特定的行,生成新文件并rsync上传

    rsync.sh #!/bin/bash tool_path=$(cd `dirname $`; pwd) eval `cat ${tool_path}/conf.properties` rsync_ ...

  9. WPF Storyboard 动画播放完毕时触发的事件

    /*故事版*/ Storyboard ClSto2; public PopUpWindow() { /*播放完毕,将当前窗体关闭*/ ClSto2.Completed += (s, e) => ...

  10. TCP/IP_网络基础知识

    今天看到k8s的网络,顿感网络知识不是特别扎实,立马回头补一下Tcp-ip知识,顺便记录下学习的过程: 计算机与网络发展的7个阶段: 批处理时代(计算机按照顺序处理,50年代)->分时系统时代( ...