MySQL Execution Plan--NOT EXISTS子查询优化
在很多业务场景中,会使用NOT EXISTS语句来确保返回数据不存在于特定集合,部分场景下NOT EXISTS语句性能较差,网上甚至存在谣言"NOT EXISTS无法走索引"。
首先需要明确的是:索引不是万能的,使用索引的执行计划并不一定就是最好的执行计划。
以某监控平台为例,使用NOT EXISTS的SQL为:
SELECT count(1)
FROM t_monitor m
WHERE NOT exists
(
SELECT 1
FROM t_alarm_realtime AS a
WHERE a.resource_id=m.resource_id
AND a.resource_type=m.resource_type
AND a.monitor_name=m.monitor_name
)
该SQL执行时间为29秒,其执行计划为:

可以发现,上面SQL中使用到索引,但是表t_monitor上影响行数较高(578436),相当于遍历表t_monitor上索引idx_id_name_type上所有数据。
对于NOT EXISTS语句,常用的优化手段之一就是将NOT EXIST语句转换为LEFT JOIN语句,如将上面的SQL转换为:
SELECT count(1)
FROM t_monitor m
LEFT JOIN t_alarm_realtime AS a
ON a.resource_id=m.resource_id
AND a.resource_type=m.resource_type
AND a.monitor_name=m.monitor_name
WHERE a.resource_id is NULL
PS1:将NOT EXISTS转换为LEFT JOIN时,需要确定两表在关联条件上的数据处于1:1或1:0,否则需要在JOIN前或JOIN后对数据进行去重操作(DISTINCT)。
改写后SQL执行时间为1.2秒,性能提升约25倍,改写后执行计划为:

粗略对比两个执行计划,会发现相似度很高,使用的索引页相同,仅仅是select_type和Extra两列存在差异

两个执行计划差异:NOT EXISTS语句使用"DEPENDENT SUBQUERY",而LEFT JOIN使用SIMPLE方式。
为什么两者会有如此大差距呢?可以通过MySQL提供的Profiling方式来查看两种方式的执行过程。
使用NOT EXIST方式的执行过程:

使用LEFT JOIN方式的执行过程:

从执行过程来看,LEFT JOIN方式的主要消耗在Sending data一项上(1.2s),而NOT EXISTS方式主要消耗在executeing和Sending data两项上,受限于Profiling只存放100行记录缘故,从Profiling中只能看到47个” executeing和Sending data”的组合项(每个组合项约50us),通过执行计划看出,外表t_monitor的数据量为578436行,忽略统计信息不准情况下,使用NOT EXISTS方式应该会产生578436个” executeing和Sending data”的组合项,总计消耗时间=50μs*578436=28921800us=28.92s。
PS2:在MySQL 5.5版本中,使用Profiling查看执行过程会返回所有的步骤,而MySQL 5.7版本中,将步骤数量控制在100行以内,避免展示过多重复步骤影响查看。
问题总结:
对于NOT EXISTS方式语句,其执行性能严重依赖于子查询的循环执行次数,即外层查询结果集的数据量:
1、当外层查询结果集的数据量N较小时执行性能较好,如有N=10执行时间为50μs*10=500us=0.005s,再加上一些额外消耗,执行结果也能在0.01秒或10毫秒内范围,这个响应时间应该能被大部分应用程序接受。
2、当外层程勋结果集的数据量N较大甚至上千万数据量时,NOT EXISTS的查询性能会变得非常糟糕,甚至会大量消耗服务器IO和CPU资源从而影响其他业务正常运行。
NOT EXISTS语句相对于LEFT JOIN语句更容易书写和便于理解,任何查询方式都有其适用场景,存在即合理。
MySQL Execution Plan--NOT EXISTS子查询优化的更多相关文章
- Execution Plan 执行计划介绍
后面的练习中需要下载 Demo 数据库, 有很多不同的版本, 可以根据个人需要下载. 下载地址 -http://msftdbprodsamples.codeplex.com/ 1. 什么是执行计划 ...
- mysql优化---in型子查询,exists子查询,from 型子查询
in型子查询引出的陷阱:(扫更少的行,不要临时表,不要文件排序就快) 题: 在ecshop商城表中,查询6号栏目的商品, (注,6号是一个大栏目) 最直观的: mysql); 误区: 给我们的感觉是, ...
- 【MySQL】MySQL中针对大数据量常用技术_创建索引+缓存配置+分库分表+子查询优化(转载)
原文地址:http://blog.csdn.net/zwan0518/article/details/11972853 目录(?)[-] 一查询优化 1创建索引 2缓存的配置 3slow_query_ ...
- MySQL实验 子查询优化双参数limit
MySQL实验 子查询优化双参数limit 没想到双参数limit还有优化的余地,为了亲眼见到,今天来亲自实验一下. 实验准备 使用MySQL官方的大数据库employees进行实验,导入该示例库 ...
- Mysql单表访问方法,索引合并,多表连接原理,基于规则的优化,子查询优化
参考书籍<mysql是怎样运行的> 非常推荐这本书,通俗易懂,但是没有讲mysql主从等内容 书中还讲解了本文没有提到的子查询优化内容, 本文只总结了常见的子查询是如何优化的 系列文章目录 ...
- postgresql子查询优化(提升子查询)
问题背景 在开发项目过程中,客户要求使用gbase8s数据库(基于informix),简单的分页页面响应很慢.排查发现分页sql是先查询出数据在外面套一层后再取多少条,如果去掉嵌套的一层,直接获取则很 ...
- in型子查询陷阱,exists子查询
in 型子查询引出的陷阱 select goods_id from goods where cat_id in (1,2,3) 直接用id,不包含子查询,不会中陷阱 题: 在ecshop商城表中,查询 ...
- 【mysql】关联查询_子查询_排序分组优化
1. 关联查询优化 1.1 left join 结论: ①在优化关联查询时,只有在被驱动表上建立索引才有效! ②left join 时,左侧的为驱动表,右侧为被驱动表! 1.2 inner join ...
- sql server 执行计划(execution plan)介绍
大纲:目的介绍sql server 中执行计划的大致使用,当遇到查询性能瓶颈时,可以发挥用处,而且带有比较详细的学习文档和计划,阅读者可以按照我计划进行,从而达到对执行计划一个比较系统的学习. 什么是 ...
随机推荐
- java servlet练习测试
步骤: 0.首先创建web project,工程名:test_servlet 1.编写Servlet,TestServlet.java文件内容: package com.ouyang.servlet; ...
- android -------- Retrofit + RxJava2.0 + Kotlin + MVP 开发的 WanAndroid 项目
简介 wanandroid项目基于 Retrofit + RxJava2.0 + Kotlin + MVP 用到的依赖 implementation 'io.reactivex.rxjava2:rxj ...
- 网络(socket)编程
一.网络协议 客户端/服务器架构 1.硬件C/S架构(打印机) 2.软件C/S架构(互联网中处处是C/S架构):B/S架构也是C/S架构的一种,B/S是浏览器/服务器 C/S架构与socket的关系: ...
- SQL Server-执行计划教会我如何创建索引
先说点废话 以前有 DBA 在身边的时候,从来不曾考虑过数据库性能的问题,但是,当一个应用程序从头到脚都由自己完成,而且数据库面对的是接近百万的数据,看着一个页面加载速度像乌龟一样,自己心里真是有种挫 ...
- ie 下date对象
var t = '2014-02-26T21:18:02.497' var a = t.replace(/(\d{4})-(\d{2})-(\d{2})T(.*)?\.(.*)/, "$1/ ...
- day057 基于对象和基于双下划线的多表查询
单表查询和多表查询的添加与查询 上述关系:author-authordetail是一对一的关系(外键在author上名为authors), book-publis ...
- 在windows下安装nvm并管理nodejs版本
不得不说,nodejs的nvm工具跟python下的mkvirtualenv 工具很像.作为立志成为伪全栈的我来说,玩玩nodejs是必不可少的.nodejs 有很多种的安装方式,下面我用nvm的方式 ...
- ef core code frist
https://docs.microsoft.com/zh-cn/ef/core/get-started/aspnetcore/new-db?view=aspnetcore-2.1 1.先创建对应的实 ...
- char与char的区别
char与varchar的区别 : char (13)长度固定, 如'www.qq.net' 存储需要空间 12个字符: varchar(13) 可变长 如'www.qq.net' 需要存储空间 9字 ...
- Eclipse错误集合
一.Could not write metadata for '/RemoteSystemsTempFiles'. 错误代码 Could not write metadata for '/Remote ...