POSTGRESQL SQL 执行用 IN 还是 EXISTS 还是 ANY

news2024/12/29 19:24:10

dbda15f4b34e39a9d59e60643a84cd65.png

开头还是介绍一下群,如果感兴趣polardb ,mongodb ,mysql ,postgresql ,redis 等有问题,有需求都可以加群群内有各大数据库行业大咖,CTO,可以解决你的问题。加群请联系 liuaustin3 ,在新加的朋友会分到3群(共950人左右 1 + 2 + 3)

POSTGRESQL SQL 查询中经常用到的一些查询使用的查询符号,如 in , exists ,any ,这些查询符号在使用中有什么性能方面的差距,以及在什么场景下适合使用,这应该是一个有意思的话题。

IN  EXISTS ANY ,三个条件操作符,分别带有不同的目的

虽然IN 和 EXISTS 本身都是从一个结果集合匹配另一个结果集合中包含相关的数据的问题,但是两个操作符号,对应的操作方法是不同的。

IN 是将外表当做一个结果集,将内表和外表进行一个笛卡尔积,所以如果内表比较小的话,则对于计算的速度是有利的。

c4123d56e7addd3cea60c93bf9b48e68.png

EXISTS 本身是循环外表,简则内表的行是否在外表中存在

我们下面先入为主的用三查询来说明

select sum(pay.amount),sta.staff_id

from payment as pay

left join staff as sta on pay.staff_id = sta.staff_id

left join (select rental_date,rental_id from rental where rental_date > '2000-09-08') as ren on pay.rental_id = ren.rental_id

group by sta.staff_id;

select sum(pay.amount),sta.staff_id

from staff as sta 

left join (

select pay_z.amount,pay_z.staff_id

from payment as pay_z where exists (select * from rental as ren where pay_z.rental_id = ren.rental_id and rental_date > '2000-09-08')) as 

pay on pay.staff_id = sta.staff_id

group by sta.staff_id;

select sum(pay.amount),pay.staff_id from 

(select pay.amount,pay.staff_id,pay.rental_id

from payment as pay where pay.staff_id in (select staff_id from staff)) as pay

left join rental as ren on ren.rental_id = pay.rental_id 

where ren.rental_date > '2000-09-08'

group by pay.staff_id;

相关查询已经有预热了查询,所以不存在第一次查询的时间的差异

3c4015bbd8be7137b3cf7cb0ce1e26e6.png

三个查询的方式 一样的查询结果,这里第一个查询时间最快,但查看执行计划,发现一个问题,虽然查询里面的rental 表并用时间进行了控制,但是在查询计划中并未有相关的表出现。经过分析在rental 表中的最早有时间的rental_date 是在 2005年5月24日所以这个条件相对于整体的SQL 是一个完全包含的结果,通过统计信息的分析,在这条SQL 里面并未涉及  rental 表与整体数据的关联。

left join (select rental_date,rental_id from rental where rental_date > '2005-09-08') as ren on pay.rental_id = ren.rental_id

af112b3961b5bf57e2c659d5e5613bcc.png

ae378f16c58d0716f9d4ea65a1071bdd.png

第二种方式,在查询中使用了exists 的方式,这里由于操作方式的变化,根据语句的逻辑整体还是先根据rental_date时间的条件进行过滤然后通过merge 的方式将 payment 表和 rental表进行条件的匹配,并且对于payment 的staff_id进行了排序,然后在和排序的 staff表进行了merge 最后产出的结果。

05c69f43a04fce7982d3464a6cd3a01c.png

第三种 查询将 EXISTS 替换成 IN 操作,这里的操作明显复杂于 EXISTS ,在rental 和payments 两个表进行merge后,在进行排序然后在对STAFF 表进行排序在对 STAFF 和结果集进行MERGE

17c2a4fe93c85e0420ae66b93cd80a2a.png

三个语句最终,还是不通过exists 和in 采用单纯的JOIN的方式的语句速度要快,因为他抛弃了rental 表的操作, 而无论采用EXISTS 或 IN 两个执行的过程是类似的,COST的值也是一样的,但是后者有极小的差异,EXISTS 占优。

在POSTGRESQL 还有一个运算操作 ANY ,通过ANY 也可以进行类似 EXISTS 或 IN 通过类似的方式进行,但不同的是 ANY 的操作余地比其他的方案要多,非等值的计算也可以通过ANY来进行。

0b64922f0eed7e9c500303705555b2ee.png

其中查询时间类似EXISTS 的查询时间。

那么下面我们变换一下查询的逻辑将等值的运算变为非等值的运算,看看这样三种方式还是否在查询时间上类似。

a7f3cf157bda3c0a69878c409580d507.png

在我们变换了查询的逻辑,将staff_id 等于1的排除在外后,查询的效率里面排名  not in 为速度最快, not exists 排名第二  , any的速度与 not exists 类似。

select sum(pay.amount),sta.staff_id

from staff as sta 

inner join (

select pay_z.amount,pay_z.staff_id

from payment as pay_z where not exists (select * from rental as ren where pay_z.rental_id = ren.rental_id and rental_date > '2000-09-08' and pay_z.staff_id = 1)) as 

pay on pay.staff_id = sta.staff_id 

group by sta.staff_id;

select sum(pay.amount),pay.staff_id from 

(select pay.amount,pay.staff_id,pay.rental_id

from payment as pay where pay.staff_id not in (select staff_id from staff where staff_id = 1)) as pay

left join rental as ren on ren.rental_id = pay.rental_id 

where ren.rental_date > '2000-09-08'

group by pay.staff_id;

select sum(pay.amount),pay.staff_id from 

(select pay.amount,pay.staff_id,pay.rental_id

from payment as pay where pay.staff_id > any (select staff_id from staff where staff_id = 1)) as pay

left join rental as ren on ren.rental_id = pay.rental_id 

where ren.rental_date > '2000-09-08'

group by pay.staff_id;

但是这里要说明,not exists 的语句变动最大,从原来的LEFT JOIN 变为了 INNER JOIN 而从人操作的逻辑来看 any 是从思维的角度最容易理解的语句的撰写的方式。

当然这里数据量不一样的情况下,可能NOT IN 就不会占据优势。

总结:

如果你想要排除一组值,NOT IN 通常是一个简单和直观的选择。

如果你想要比较一个值与子查询的结果集中的任何值,ANY 是一种常用的方法。

如果你只是想确定子查询是否返回结果,并且不关心具体的匹配记录,NOT EXISTS 是一个适当的选择。

三种数据的处理方式中,根据数据量和表前后的关系,可以在性能差的时候进行一些语句查询方式的变更,看看是否可以提高相关的语句查询的效率。但根据上面的案例,如果可以直接使用 JOIN ,那么还是直接使用JOIN 的方式在部分情况下,更快。

acf8505045c50342ba86bfd2cd2b4db0.png

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/721502.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【后端面经-计算机基础】HTTP和TCP的区别

【后端面经-计算机基础】HTTP和TCP的区别 文章目录 【后端面经-计算机基础】HTTP和TCP的区别1. OSI七层模型和相关协议2. TCP协议2.1 特点:2.2 报文格式2.3 三次握手和四次挥手 3. HTTP协议3.1 特点3.2 报文格式3.2 https和http 4. HTTP vs TCP5. 面试模拟参考资料 …

全网最牛,python接口自动化测试-接口sign签名(实战撸码)

目录:导读 前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结(尾部小惊喜) 前言 一般公司对外的接…

groupkfold 报错:raise keyerror(f“{not foud} not in index“)

【1】使用groupkfold 的时候出现以上报错:索引错误,groups的索引和x y 的不对应 【2】源代码: 【3】进行修改: 可以成功索引!!!

tomcat下上传html

html 最基本结构服务器xshelltomcat 下载是否可以访问到服务器上传html html 最基本结构 .html 后缀名 <!DOCTYPE HTML> <html><head><meta charset"utf-8"> <title>2306</title></head><body>大家好&#xff01;…

C++图形开发(7):能进行抛物线运动且触墙能反弹的小球

今天来实现一下触墙能反弹的小球、 我们之前所实现的都只是小球的上下&#xff0c;也就是y轴方向的运动&#xff08;详见&#xff1a;C图形开发&#xff08;6&#xff09;&#xff1a;落下后能弹起的小球&#xff09;&#xff0c;那么要使小球能够呈抛物线状运动&#xff0c;我…

Failed to start connector [Connector[HTTP/1.1-8080]]

1、解决Web server failed to start. Port 8080 was already in use 2、SpringBoot启动报错:“Error starting ApplicationContext. To display the conditions report re-run your application with ‘debug’ enabled.” 3、Failed to start end point associated with Proto…

015-从零搭建微服务-远程调用(一)

写在最前 如果这个项目让你有所收获&#xff0c;记得 Star 关注哦&#xff0c;这对我是非常不错的鼓励与支持。 源码地址&#xff08;后端&#xff09;&#xff1a;https://gitee.com/csps/mingyue 源码地址&#xff08;前端&#xff09;&#xff1a;https://gitee.com/csps…

如何利用Spine制作简单的2D骨骼动画

在2D游戏中&#xff0c;我们经常看到各种各样的角色动画。动画能给游戏带来生机和灵气。创作一段美妙的动画&#xff0c;不仅需要强大的软件工具&#xff0c;更需要一套完善的工作流程。 Spine就是一款针对游戏开发的2D骨骼动画编辑工具。Spine 可以提供更高效和简洁 的工作流…

【STM32智能车】寻迹模块

【STM32智能车】寻迹模块 寻迹模块 传感器原理接线说明 智能车寻迹是一种机器人控制技术&#xff0c;它通过使用传感器和程序算法&#xff0c;使汽车能够在行驶过程中识别出路径上的黑线&#xff0c;并沿着该线路行驶。 智能车寻迹常用于竞赛或教育用途&#xff0c;可以提高学生…

【学习心得】Virtual Studio Code下载安装与简单设置

一、下载 1、vs code 官网&#xff1a;https://code.visualstudio.com/ 二、安装 1、双击安装文件开始安装。 2、同意协议开始下一步。 3、选择你自己想要安装的路径。 4、勾选这三个&#xff0c;方便右键在vs code 中打开文件或文件夹。 5、安装步骤几乎没有坑&#xff0c;直…

探究低代码开发平台的价值所在,为企业带来哪些优势?

随着数字化转型的加速&#xff0c;企业和组织需要以更快的速度交付新的软件应用程序&#xff0c;以保持竞争力和创新性。然而&#xff0c;传统的软件开发模式已经不再适用于当前的快节奏商业环境。在这种背景下&#xff0c;低代码开发平台日益成为软件开发的热门趋势&#xff0…

【JavaWeb基础】三层架构

一、知识点整理 三层架构的含义 Controller: 控制层,接收前端发送的请求,对请求进行处理,并响应数据。 Service:业务逻辑层,处理具体的业务逻辑。 Dao(Data Access Object): 数据访问层(持久层),负责数据访问操作,包括数据的增、删、改、查。 二、代码实现 原EmpController.…

spring整合logBack日志框架:

1. SLF4J简介 SLF4J&#xff08;Simple Logging Facade for Java&#xff09;是一种日志规范&#xff0c;类似于JDBC&#xff0c;我们常用的日志log4j、logback等都实现了这个规范&#xff0c;所以我们可以直接使用SLF4J的规范来使用日志。 2. logback和log4j 它们是同一个作…

【hadoop】大数据的几个基本概念

大数据的几个基本概念 数据仓库的基本概念数据仓库与大数据OLTP与OLAP 数据仓库的基本概念 数据仓库&#xff0c;英文名称为Data Warehouse&#xff0c;可简写为DW或DWH。数据仓库&#xff0c;是为企业所有级别的决策制定过程&#xff0c;提供所有类型数据支持的战略集合。 本…

堆排序算法及其稳定性分析

堆排序算法及其稳定性分析 什么是堆排序&#xff1f; 堆排序是利用数据结构堆而设计的一种排序算法。 堆分为两种&#xff0c;大顶堆和小顶堆。 所谓大顶堆就是每个节点的值都大于或者等于其左右孩子节点的值。 小顶堆则是相反的&#xff0c;每个节点的值都小于或者等于其…

超全整理,接口测试实战详细(实例)一篇打通...

目录&#xff1a;导读 前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结&#xff08;尾部小惊喜&#xff09; 前言 1、接口测试范围 …

Git无法上传删除 Commit里面有大文件

1.Bug描述 因为在一次提交中不小心把一个打包的aab文件弄到commit文件里了&#xff0c;于是在上传的时候push rejected 了。 因为GitHub的文件上限是100M&#xff0c;但是打的包太大了&#xff0c;有170M&#xff0c;所以是不能上传的&#xff0c;但是又是已经在Commit历史中了…

rsync增量备份工具

目录 一、概述 二、配置 rsync 源服务器 1.查看rsync配置文件位置 2.修改 /etc/rsync.conf 配置文件 3.为备份账户创建数据文件 4.保证所有用户对源目录都有读取权限 5.启动 rsync 服务 三、发起端 1.rsync命令 2.将指定的资源远程同步到本地/opt 目录下进行备份。 3.将…

【Docker】docker安装nginx及端口映射相关配置

前言&#xff1a; 最近&#xff0c;在一台新服务器上准备运行一个前端vue项目&#xff0c;服务器上安装了docker&#xff0c;想要尝试试通过docker安装nginx的并运行项目&#xff0c;以下是操作步骤 操作步骤&#xff1a; 一、安装nginx 1、拉取镜像 从docker仓库里拉取最…

unaipp打包app启动界面配置

1、配置代码 2、IOS端启动界面demo参考 iOS平台自定义storyboard启动界面 - DCloud问答