MySQL not exists 与索引的关系

MySQL not exists 与索引的关系

在一些业务场景中,会使用NOT EXISTS语句确保返回数据不存在于特定集合,部分同事会发现NOT EXISTS有些场景性能较差,甚至有些网上谣言说”NOT EXISTS不走索引”,哪对于NOT EXISTS语句,我们如何优化呢?

以今天优化的SQL为例,优化前SQL为:

SELECT count(1) FROM t_monitV b ; l . v bor m WHERE NOT exists (  SELECT 1   FROM t_alarm_r/ 6 ` (ealtime AS a   WHERE a.resource_id=m.resource_id   AND a.resource_type=m.ret d D 4 9 7 X w Jsource_type   AND a.monitor_name=m.monitor_name)

我们使用LEFT JOIN方式进行优化,优化后SQL为:

SELECT count(1) FROM t_monitor m LEFT JOIN t_alarm_realtime AS a    ON a.resouX k ] 6rce_id=m.resource_id   AND a.resourcei 9 J = r A 7 O_type=m.resource_type   AND a.monitor_name=m.monit5 S a Y !or_name WHX s l A cERE a.resource_id is NULL

优化效果:

优化前执行时间29秒以上,优化后1.2秒,优k - 1 ( I q w Y +化提升25倍。

NOT EXJ J 3 MISTS真的i J U不走索引么?v 6 d

查看两种SQLs H Q [ ; L V的执行计划!

使用NOT EXIST方式的执a O T x $ _ J行计划:

MySQL not exists 与索引的关系

使用LEFT JOIN方式的执行计划:

MySQL not exists 与索引的关系

从执行计划来看,两个表都使用了索引,区别在于NOT EXISTS使用“DEPENDENT SUBQUERY| D $ + . E % ?”方式,而LEFT JOIN使用普通表关联的方式。

推荐看下:为什么索引能提高查询速度?

通过MySQL提供的Profip 0 Y ulingu F A方式来查看两种方式的执行过程。

使用w h 6 a # 0NOT EXIST方式的执行过程:

MySQL not exists 与索引的关系

使用LEFT JOINy 2 + Z方式的执行过程:

从执行过程来看,LEFT JOIN方式的主要消耗在Sending data一项上(1.2s),而NOT EXISTS方式主要消耗在executeing和Sending data两项上,] l d [ 2受限于Profiling只存放100行记录缘故。

从Profiling中只能看到47个” executeing和Sending data”的组合项(每个组合项约50us)W X 2 H v T ,通过执行计划看出,外表t_mo( Z gnitor的数据量为578436行,忽略统计信息不准情况6 _ ( `下,使用NOT EXIH 9 C n ! @ a ESTS方式应该会产生578436个” executeing和Sending data”的组合项,总计消耗时间=50s*578436=28921800us=28.92s。

从上面执行过程可以推断出:

使用NOT EXISTS方式的执行性能严重依赖于NOT EXISTS子查询的执行次数即外层查询结果集的数据量。

  1. 当外层查询结Q h l , 6果集的数据量N较小时执行性能较好,如有N=10执行时间为50s*10=500us=0.005s,再加上f & ! k V s u 7一些额外消耗,执行结果也能在0.01秒或10毫秒内范围,这个响应时间应该能被大部分应用程序接受。

  2. 当外层程勋结果集的数据量N较大甚至上千万数据量时,NOT EXISTS的. V * O $查询性能会变得非常糟糕,甚至会大量消耗服务器IO和CPU资源从而影响其他业务正常运行。

除上述问题外,在优化过程中发现本应该存储相同数据的resource_id列在两个表中定义不同,一表为VARCHARe k ] T Y D - ul ( B X另外一表为BIGINT,外部结果集的字段类型和NOT EXIST字表中字段类型不同导致NOT EXISTSo E v子查询中无法使用索引,使得! e *子查询性能较差,最终影响整个查询的i e ? V r T 2 p {执行性能。

京东商城也曾出现过大量类似案例,一些表使用VARCHAR来存放订单号,而另一些表使用BIGINT来存放,在两表进行管理时性能极差,希望研发同. R 0 5 o D [事引以) D ~ - x为戒。关注公众号Javv 0 | f Fa技术栈回复m36获取一份MySQL研发军规。

相关学习推荐:mysql视频教程

以上就^ Z p } ? { s Q是MySQL not exists 与索引的关系的详细内容。