在我们平时写SQL时,如果遇到需要排除某些数据时,往往使用id <> xxx and id <> xxx,进而改进为id not in (xxx, xxx);

这样写没有问题,而且简化了SQL,但是往往有些极端情况,使用not in就会造成极大的性能损耗,例如:

select * from test where id not in (select id from test_back) and info like '%test%';

这样的话select id from test_back将成为一个子查询,而且不会走索引,每次走一遍全表扫描。

每一条满足info like '%test%'的记录都会去调用这个方法去判断id是否不在子查询中,具体的执行计划见下面的例子。

改进方法:

1)使用test和test_back进行联合查询,id <> id明显是不行的,这样只会判断同一关联条件下的一行中的id是否相同,无法做到排除某些id。

2)正确的方式应该使用not exists,将条件下推到里面,就不会出现子查询了:

select * from test  t1 where info like '%test%' and not exits (select 1 from test_back t2 where t2.id = t1.id);

apple=# \d test
Table "public.test"
Column | Type | Collation | Nullable | Default
--------+---------+-----------+----------+---------
id | integer | | not null |
info | text | | |
Indexes:
"test_pkey" PRIMARY KEY, btree (id) apple=# truncate test;
TRUNCATE TABLE
apple=# insert into test select generate_series(1, 100), 'test'||round(random()*10000)::text;
INSERT 0 100
apple=# select * from test limit 1;
id | info
----+----------
1 | test9526
(1 row) apple=# insert into test select generate_series(101, 200), 'tes'||round(random()*10000)::text;
INSERT 0 100
apple=# create table test_back as select * from test where id between 50 and 70;
SELECT 21
apple=# explain select * from test where id not in (select id from test_back) and info like '%test%';
QUERY PLAN
---------------------------------------------------------------------
Seq Scan on test (cost=25.88..30.88 rows=49 width=12)
Filter: ((NOT (hashed SubPlan 1)) AND (info ~~ '%test%'::text))
SubPlan 1
-> Seq Scan on test_back (cost=0.00..22.70 rows=1270 width=4)
(4 rows)
apple=# explain select * from test t1 where info like '%test%' and not exists (select 1 from test_back t2 where t2.id = t1.id);
QUERY PLAN
-------------------------------------------------------------------------
Hash Anti Join (cost=1.47..7.13 rows=89 width=12)
Hash Cond: (t1.id = t2.id)
-> Seq Scan on test t1 (cost=0.00..4.50 rows=99 width=12)
Filter: (info ~~ '%test%'::text)
-> Hash (cost=1.21..1.21 rows=21 width=4)
-> Seq Scan on test_back t2 (cost=0.00..1.21 rows=21 width=4)
(6 rows)

例子里面没有建索引,建索引后,这种优化方式效果更好。

那么进一步扩展来说:

1)!= 不是标准的SQL,<>才是,这两个在PostgreSQL中是等效的。

2)exits和not exits的意思是逐条将条件下放到判断条件,而jion方式是先对表进行笛卡尔积,然后判断同行之间的各列值是否满足关系。

PostgreSQL SQL优化之NOT IN问题的更多相关文章

  1. SQL优化技巧

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

  2. 《高性能SQL调优精要与案例解析》一书谈主流关系库SQL调优(SQL TUNING或SQL优化)核心机制之——索引(index)

    继<高性能SQL调优精要与案例解析>一书谈SQL调优(SQL TUNING或SQL优化),我们今天就谈谈各主流关系库中,占据SQL调优技术和工作半壁江山的.最重要的核心机制之一——索引(i ...

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

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

  4. sql 优化

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

  5. SQL 优化总结

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

  6. (转)SQL 优化原则

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

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

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

  8. mysql sql优化实例

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

  9. ORACLE常用SQL优化hint语句

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

随机推荐

  1. luogu 1876 开灯 约数+打表

    打表后发现答案都是完全平方数,直接输出即可. #include <cstdio> #include <algorithm> using namespace std; int m ...

  2. HDU 1711:Number Sequence(KMP)

    Number Sequence Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) ...

  3. ERROR 1130 (HY000): Host 'test177' is not allowed to connect to this MySQL server

    异常 在测试环境新搭建的MySQL服务端,启动后登陆MySQL如下异常: [root@test177 ~]# mysql -u root -po2jSLWw0ni -h test177 mysql: ...

  4. Java线程中的异常处理

    对于对线程,当主线程中有子线程运行出现异常时,主线程是不能捕获到该异常的,子线程会直接退出,不会记录任何日志. 解决: 1.子线程中try catch. 2.设置线程的未捕获异常处理器,Uncaugh ...

  5. setHasFixedSize(true)的意义 (转)

    RecyclerView setHasFixedSize(true)的意义 2017年07月07日 16:23:04 阅读数:6831 <span style="font-size:1 ...

  6. jxbrowser 实现自定义右键菜单

    https://blog.csdn.net/shuaizai88/article/details/73743691 public static void main(String[] args) { J ...

  7. linux常用命令(13)tail命令

    tail 命令从指定点开始将文件写到标准输出.使用tail命令的-f选项可以方便的查阅正在改变的日志文件,tail -f filename会把filename里最尾部的内容显示在屏幕上,并且不但刷新, ...

  8. Oracle11g安装出现时未能满足某些最低安装要求

    需要开启C盘共享,才能检测硬件是否满足要求.cmd命令:net share c$=c::或者勾选全部忽略,继续下一步安装. 可参考https://blog.csdn.net/huazicomeon/a ...

  9. springboot整合mybatis时java.sql.SQLException: The server time zone value 'Öйú±ê׼ʱ¼ä' is unrecognized or represents more than one time zone.

    时区问题造成的,解决方法是在数据源配置文件中在数据库链接处增加参数&serverTimezone=GMT%2B8对时区进行配置,配置为东八区. 修改前:spring.datasource.ur ...

  10. Day3 && Day4

    本章内容对我来说真的是学的稀里糊涂的,除了前两题吭哧吭哧独立完成,第三题参考了别人的思路外,其余题目均是现学现卖,有点迷啊.所以写这篇博客的目的是先记录下聚聚们对本章内容相关重点的要求,并搜集一些相关 ...