• 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语句更容易书写和便于理解,任何查询方式都有其适用场景,存在即合理。

  • 相关阅读:
    java 读取src下的配置文件
    图书管理系统
    StaticDemo
    MatixDemo
    Magics
    GetPrime
    ConWithThis
    TestTHIS
    ConstructorOverLoad
    Sequence
  • 原文地址:https://www.cnblogs.com/gaogao67/p/10721052.html
Copyright © 2020-2023  润新知