SQL优化--inner、left join替换in、not in、except
SQL优化--inner、left join替换in、not in、except
新系统上线,用户基数16万,各种查询timeout。打开砂锅问到底,直接看sql语句吧,都是泪呀,一大堆innot inexcept。这里总结一下,怎么替换掉innot inexcept。
- in/except->left join
查询目的:
根据
客户表(Customer,按照站点、册本划分,16万数据)
水表表(Meter,16万数据)
水表抄表数据表(Meter_Data,远传表每天更新,27万数据)
关联查询,查询某天某个册本下水表未上传抄表数据的用户。
原查询结构
select *
from Customer cs
where
cs.Group_No = '册本编号' and
cs.Customer_No in
(
select Customer_No
from Customer cs
left join Meter me on cs.Customer_No = me.Customer_No
where cs.Group_No = '册本编号'
except
select Customer_No
from Customer cs
left join Meter me on cs.Customer_No = me.Customer_No
inner join Meter_data md on me.meter_no = md.meter_no and md.date = '2019-04-09'
where cs.Group_NO='册本编号'
)
原查询思路
查询出目标册本已上传数据的用户编号
select Customer_No
from Customer cs
left join Meter me on cs.Customer_No = me.Customer_No
inner join Meter_data md on me.meter_no = md.meter_no and md.date = '2019-04-09'
where cs.Group_NO='册本编号'
查询出目标册本全部用户编号
select Customer_No
from Customer cs
left join Meter me on cs.Customer_No = me.Customer_No
where cs.Group_No = '册本编号'
全部用户编号中排除已上传数据的用户编号,即为未上传数据的用户编号
全部用户编号 except 已抄表的用户编号
查询出在未抄表用户编号集合中的用户信息。
select *
from Customer cs
where
cs.Group_No = '册本编号' and
cs.Customer_No in
(全部用户编号 except 已抄表的用户编号)
思路倒是没有问题,但是in+except查询效率不要太慢了,本来想测试个时间,结果执行了几分钟愣是没出结果,直接终止掉了
优化查询结构
其实innot inexcept这些语法在查询中使用,效率不高是公认的事实,但是可能是由于语义比较明显吧,很多人还是喜欢这样用。我们这里使用left join来替代in+except。这里就来改掉上面的查询:
select cs.*
from Customer cs
left join Meter me on cs.Customer_No = me.Customer_No
left join Meter_data md on me.meter_no = md.meter_no and md.date = '2019-04-09'
where cs.Group_NO='册本编号' and md.meter_no is null;
优化查询思路
用left join代替in+except,通过left join获取目标册本下全部用户的信息,并与当天上传的抄表数据进行连接;
连接中,右表为空即抄表数据为空的,即为当前未上传数据的客户信息;
left join on expression where expression 执行时,首先确保左表数据全部返回,然后应用on后指定的条件。因此,on的条件如果是对左表数据的过滤,是无效的;对右表数据的过滤是有效的。对左表数据的过滤条件,需要放到where条件中。
- not in->left join
上面in+except的写法,可以使用not in简化一下,但是一样效率不高。这里想要说明的是not in也可以很方便的使用left join替换。
not in结构
select *
from Customer cs
where
cs.Group_No = '册本编号' and
cs.Customer_No not in
(
select Customer_No
from Customer cs
left join Meter me on cs.Customer_No = me.Customer_No
inner join Meter_data md on me.meter_no = md.meter_no and md.date = '2019-04-09'
where cs.Group_NO='册本编号'
)
left join结构
select cs.*
from Customer cs
left join Meter me on cs.Customer_No = me.Customer_No
left join Meter_data md on me.meter_no = md.meter_no and md.date = '2019-04-09'
where cs.Group_NO='册本编号' and md.meter_no is null;
- in->inner join
查询目的
还是上面的查询背景,这里查询某天某个册本已经上传抄表数据的用户信息。
in结构
select *
from Customer cs
where
cs.Group_No = '册本编号' and
cs.Customer_No in
(
select Customer_No
from Customer cs
left join Meter me on cs.Customer_No = me.Customer_No
inner join Meter_data md on me.meter_no = md.meter_no and md.date = '2019-04-09'
where cs.Group_NO='册本编号'
)
这里使用in不够高效,但是我们使用left join是否可以呢?
left join结构
select cs.*
from Customer cs
left join Meter me on cs.Customer_No = me.Customer_No
left join Meter_data md on me.meter_no = md.meter_no and md.date = '2019-04-09'
where cs.Group_NO='册本编号' and md.meter_no is not null;
left join结构的话,这里需要使用is not null作为筛选条件。但是is not null同样非常低效。因此我们使用inner join
inner join结构
select cs.*
from Customer cs
left join Meter me on cs.Customer_No = me.Customer_No
inner join Meter_data md on me.meter_no = md.meter_no and md.date = '2019-04-09'
where cs.Group_NO='册本编号';
inner join通过连接操作,直接获取到已上传抄表数据的用户信息。
- not in -> in -> inner join
前面的查询场景中,我们默认的条件是未上传抄表数据的用户,当天在meter_data表是没有记录的。现在假设我们每天凌晨初始化meter_data表,设置抄表数值默认为零,抄表数据上传默认为state=0未上传。上传后,更新抄表数值和抄表状态state=1。
这时,我们来优化上面的not in查询结构还有另外一种思路。
not in结构
select *
from Customer cs
where
cs.Group_No = '册本编号' and
cs.Customer_No not in
(
select Customer_No
from Customer cs
left join Meter me on cs.Customer_No = me.Customer_No
inner join Meter_data md on me.meter_no = md.meter_no and md.date = '2019-04-09'
where cs.Group_NO='册本编号' and meter.state=1
)
in结构
通过筛选条件取反,变换not in->in
select *
from Customer cs
where
cs.Group_No = '册本编号' and
cs.Customer_No in
(
select Customer_No
from Customer cs
left join Meter me on cs.Customer_No = me.Customer_No
inner join Meter_data md on me.meter_no = md.meter_no and md.date = '2019-04-09'
where cs.Group_NO='册本编号' and meter.state=0
)
inner join结构
select cs.*
from Customer cs
left join Meter me on cs.Customer_No = me.Customer_No
inner join Meter_data md on me.meter_no = md.meter_no and md.date = '2019-04-09'
where cs.Group_NO='册本编号' and meter.state=0;
- 总结如下
上面的查询结构拆分出来后,大家可能觉得这么简单的sql怎么可能写成这个沙雕。其实真实业务系统,还有关联其他将近10张表。这里想说的是,在innot inexcept这种查询结构时,如果涉及到的数据量较大,建议坚决用连接替换。
... in (all except sub)... 查询结构可以转换为->left join
... not in ... 查询结构可以转换为->left join
... not in ... 查询也可以转换为 in -> inner join,这里需要确认转换查询条件时,是否有对应的数据
... in 查询结构可以转换为->inner join
原文地址https://www.cnblogs.com/zhangdk/p/notintoleftjoin.html
SQL优化--inner、left join替换in、not in、except相关推荐
- 19_clickhouse,数据查询与写入优化,分布式子查询优化,外部聚合/排序优化,基于JOIN引擎的优化,SQL优化案例,物化视图提速,查询优化常用经验法则,选择和主键不一样的排序键,数据入库优化
25.数据查询与写入优化 25.1.分布式子查询优化 25.1.1.分布式表的IN查询示例1(普通IN子查询.IN子查询为本地表) 25.1.2.分布式表的IN查询示例2(普通IN子查询.IN子查询为 ...
- inner join 和 exists 效率_19 个让 MySQL 效率提高 3 倍的 SQL 优化技巧
在介绍具体的 SQL 调优的方法前,我们先来简单了解下 MySQL 调优金字塔理论. 如上图所示,数据库优化维度有四个:硬件.系统配置.数据库表结构.SQL 及索引. 优化成本: 硬件>系统配置 ...
- SQL优化器原理 - Auto Hash Join
这是MaxCompute有关SQL优化器原理的系列文章之一.我们会陆续推出SQL优化器有关优化规则和框架的其他文章.添加钉钉群"关系代数优化技术"(群号11719083)可以获取最 ...
- 游标sql server_了解游标并将其替换为SQL Server中的JOIN
游标sql server Relational database management systems including SQL Server are very good at processing ...
- 从零开始java数据库SQL优化(二):多个LEFT JOIN的SQL优化
一:场景 我代码里需要在用户登录时将所有用户相关的用户,角色,部门,岗位,权限(其中权限放在菜单中,每2张表有一张关联表),不多说直接上SQL SELECT a.fk_user_id AS " ...
- SQL优化大神带你写有趣的SQL(6) SELF JOIN的应用
大家好,我是知数堂SQL 优化班老师 网名:骑龟的兔子 今天给大家,带来的是 SELF JOIN的应用 下面是,表结构和,INSERT 语句脚本. create table t0718 (idx in ...
- 使用mybatis-plus的分页插件在开启join优化后,当出现cs、ur、uu等 隔离级别的关键字sql优化时会出现大量警告
版本 <dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-boot- ...
- SQL优化(一) Merge Join vs. Hash Join vs. Nested Loop
本文介绍了Merge Join,Hash Join,Nested Loop这三种数据库Join方式的工作原理,并通过实验进一步说明了其适用范围. 原创文章,转载请务必将下面这段话置于文章开头处(保留超 ...
- MySQL进阶SQL优化
MySQL进阶SQL优化 查询效率分析: 子查询为确保消除重复值,必须为外部查询的每个结果都处理嵌套查询.在这种情况下可以考虑用联接查询来取代. 如果要用子查询,那就用EXISTS替代IN.用NOT ...
最新文章
- Linux-Ubuntu操作记录
- 2018年终总结之AI领域开源框架汇总
- Altium Designer唤出关掉的窗口
- gitlab 添加本地项目
- mysql四种事务隔离级别
- UVA4671 K-neighbor substrings FFT+字符串hash
- 第十二章 图形用户界面
- 诗与远方:无题(七十七)- 远方
- Effictive Java学习笔记1:创建和销毁对象
- java输出杨辉三角_使用Java输出杨辉三角
- 什么是REST风格? 什么是RESTFUL?(一篇全读懂)
- 【区块链108将】区块链追溯产品起源,让每一个产品都是放心产品
- 华为手机坏了数据怎么导出_苹果手机的语音备忘录怎么导出来?
- 磁盘坏道的检测及修复
- 汇编基址变址寻址方式的使用
- Niagara Networks和Fortinet安全解决方案
- 计算机网络第七版(谢希仁) 第一章 概述 1-10,1-17作业答案
- vue实现星级评价及上传多张图片等功能(类似淘宝商品评价页面)
- c/c++:UDP(udp通信、广播、组播),本地套接字
- 西门子1200与国产机器人通讯/实现机床上下料加工,中文注释,博图V15.1