站保站

服务市场
  • 网站市场
  • 单机游戏
  • 平台大厅
  • 转让市场
  • 发卡市场
  • 广告市场
  • 下载市场
  • 收录市场
  • 本站平台
    平台客服
    微信Q群



    平台微博/weibo    平台微信/公众号    平台抖音/快手   
    曝光台    保障    地图   
    上传资源 快速赚钱
    站保站    登录      |  注册  |  

    只需一步,快速开始!

     找回密码   |   协议
    热门搜索: 网站开发 App报毒 挖矿源码 代办资质

    SQL优化案例(2):OR条件优化

    • 时间:2020-10-27 19:16 编辑:云掣YUNCHE 来源: 阅读:70
    • 扫一扫,手机访问
    摘要:

    接下来上一篇文章《 SQL优化案例(1):隐式转换》的介绍,此处内容围绕OR的优化展开。

    在MySQL中,同样的查询条件,如果变换OR在SQL语句中的位置,那么查询的结果也会有差异,在多个复杂的情况下,可能会带来索引选择不佳的性能隐患,为了避免执行效率大幅度下降的问题,我们可以适当考虑使用统一所有对查询逻辑复杂的SQL进行分离。

    常见OR使用场景,请阅读以下案例。

    案例一:不同列使用OR条件查询

    1.待优化场景

    SELECT
    ..
    ..
     FROM`t1` a
     WHERE a.token= '16149684'
     AND a.store_id= '242950'
     AND(a.registrationId IS NOT NULL
     AND a.registrationId<> '')
     OR a.uid= 308475
     AND a.registrationId IS NOT NULL
     AND a.registrationId<> ''
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    执行计划

    +--------------+-----------------------+-----------------+----------------+-------------------+-------------------+---------------+----------------+---------------------------------------------+
    | id           | select_type           | table           | type           | key               | key_len           | ref           | rows           | Extra                                       |
    +--------------+-----------------------+-----------------+----------------+-------------------+-------------------+---------------+----------------+---------------------------------------------+
    | 1            | SIMPLE                | a               | range          |idx_registrationid | 99                |               | 100445         | Using index condition; Using where          |
    +--------------+-----------------------+-----------------+----------------+-------------------+-------------------+---------------+----------------+---------------------------------------------+
    
    • 1
    • 2
    • 3
    • 4
    • 5

    共返回1行记录,花费 5 ms 。

    2.场景解析

    从查询条件中可以研磨令牌和uid过滤性都非常好,但是由于使用了,或者,需要采用索引合并的方法才能获得比较好的性能。但在实际执行过程中MySQL优化器替代选择了使用registrationId的索引,导致SQL的性能很差。

    3.场景优化

    我们将SQL改写成union all的形式。

    SELECT
    ...
    ...
    FROM`t1` a
    WHERE a.token = '16054473'
    AND a.store_id = '138343'
    AND b.is_refund = 1
    AND (a.registrationId IS NOT NULL
    AND a.registrationId <> '')
    union all
    SELECT
    ...
    ...
    FROM`t1` a
    where a.uid = 181579
    AND a.registrationId IS NOT NULL
    AND a.registrationId <> ''
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    +--------------+-----------------------+-----------------+----------------+------------------------------+---------------+-------------------+------------------------------+----------------+------------------------------------+
    | id           | select_type           | table           | type           | possible_keys                | key           | key_len           | ref                          | rows           | Extra                              |
    +--------------+-----------------------+-----------------+----------------+------------------------------+---------------+-------------------+------------------------------+----------------+------------------------------------+
    | 1            | PRIMARY               | a               | ref            | IDX_TOKEN,IDX_STORE_ID_TOKEN | IDX_TOKEN     | 63                | const                        | 1              | Using index condition; Using where |
    | 1            | PRIMARY               | b               | eq_ref         | PRIMARY                      | PRIMARY       | 4                 | youdian_life_sewsq.a.role_id | 1              | Using where                        |
    | 2            | UNION                 | a               | const          | PRIMARY                      | PRIMARY       | 4                 | const                        | 1              |                                    |
    | 2            | UNION                 | b               | const          | PRIMARY                      | PRIMARY       | 4                 | const                        | 0              | unique row not found               |
    |              | UNION RESULT          | <union1,2>      | ALL            |                              |               |                   |                              |                | Using temporary                    |
    +--------------+-----------------------+-----------------+----------------+------------------------------+---------------+-------------------+------------------------------+----------------+------------------------------------+
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    共返回5行记录,花费 5 ms 。

    通过对比优化前后的执行计划,可以明显修剪,将SQL合并成两个子查询,再使用union对结果进行合并,稳定性和安全性更好,性能更高。

    案例二:同一列使用OR查询条件

    1.待优化场景

    select
    ....
    ....
    from
    t1 as mci
    left join t1 as ccv2_1 on ccv2_1.unique_no = mci=category_no1
    left join t1 as ccv2_2 on ccv2_2.unique_no = mci=category_no2
    left join t1 as ccv2_3 on ccv2_3.unique_no = mci=category_no3
    left join(
     select product_id,
     count(0) count
     from t2 pprod
     inner join t3 pinfo on pinfo.promotion_id = pprod.promotion_id
     and pprod.is_enable =1
     and ppinfo.is_enable=1
     and pinfo.belong_t0 =1
     and pinfo.end_time >=now()
     and not (
     pinfo.onshelv_time>'2019-06-30 00:00:00'
     or pinfo.end_time>'2018-12-05 00:00:00'
     )group by pprod.product_id
    )as pc on pc.product_id = mci.product_id
    where mci.is_enable =0
    and mci.comodifty_type in ('1', '5', '6')
    and (pc.count =0 or pc.count isnull ) limit 0,5;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25

    执行计划

    2.场景解析

    本例的SQL查询中有一个子查询,子查询被当成成驱动表,产生了auto_key,通过SQL进行进行测试,验证主要是(pc.count = 0或pc.count为null)会影响到整个SQL的性能,需要进行比较改写。

    3.场景优化

    首先我们可以单独思考(pc.count = 0或pc.count为null)如何进行优化?先写一个类似的SQL

    Select col from test where col =100 or col is null;
    +--------+
    | col    |
    +--------+
    |    100 |
    |   NULL |
    +--------+
    2 rows in set (0.00 sec)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    这个时候我们看到的其实是同一个列,但对应不同的值,这种情况可以利用case when进行转换。

    Select col From test where case when col is null then 100 else col =100 end;
    +--------+
    | col    |
    +--------+
    |    100 |
    |   NULL |
    +--------+
    2 rows in set (0.00 sec)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    再回到原始SQL进行改写。

    select
    ....
    ....
    from
    t1 as mci
    left join t1 as ccv2_1 on ccv2_1.unique_no = mci=category_no1
    left join t1 as ccv2_2 on ccv2_2.unique_no = mci=category_no2
    left join t1 as ccv2_3 on ccv2_3.unique_no = mci=category_no3
    left join(
     select product_id,
     count(0) count
     from t2 pprod
     inner join t3 pinfo on pinfo.promotion_id = pprod.promotion_id
     and pprod.is_enable =1
     and ppinfo.is_enable=1
     and pinfo.belong_t0 =1
     and pinfo.end_time >=now()
     and not (
     pinfo.onshelv_time>'2019-06-30 00:00:00'
     or pinfo.end_time>'2018-12-05 00:00:00'
     )group by pprod.product_id
    )as pc on pc.product_id = mci.product_id
    where mci.is_enable =0
    and mci.comodifty_type in ('1', '5', '6')
    and case when pc.count is null then 0 else pc.count end=0 limit 0,5;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25

    可以抛光优化后的SQL比原始SQL快了30秒,执行效率提升约50倍。

    案例三:优化关联SQL OR条件

    1.待优化场景

    SELECT user_msg.msg_id AS ‘msg_id’, user_msg.content AS ‘msg_content’, …
    FROM user_msg
    LEFT JOIN user ON user_msg.user_id = user.user_id
    LEFT JOIN group ON user_msg.group_id = group.group_id
    WHERE user_msg.gmt_modified >= date_sub('2018-03-29 09:31:44', INTERVAL30SECOND)
    OR user.gmt_modified >= date_sub('2018-03-29 09:31:44', INTERVAL 30 SECOND)
    OR group.gmt_modified >= date_sub('2018-03-29 09:31:44', INTERVAL 30 SECOND)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    2.场景解析

    我们仔细分析上述查询语句,发现虽然业务逻辑只需要查询半分钟内修改的数据,但执行过程却必须对所有的数据进行关联操作,带来的性能损失。

    3.场景优化

    我们对原始SQL进行分解操作,第一部分sql-01如下:

    SELECT user_msg.msg_id AS ‘msg_id’, user_msg.content AS ‘msg_content’, …
    FROM user_msg
    LEFT JOIN user ON user_msg.user_id = user.user_id
    LEFT JOIN group ON user_msg.group_id = group.group_id
    WHERE user_msg.gmt_modified >= date_sub('2018-03-29 09:31:44', INTERVAL 30 SECOND)
    
    • 1
    • 2
    • 3
    • 4
    • 5

    sql-01以user_msg表为驱动,使用gmt_modified索引过滤最新数据。

    第二部分sql-02如下:

    SELECT user_msg.msg_id AS ‘msg_id’, user_msg.content AS ‘msg_content’, …
    FROM user_msg
    LEFT JOIN user ON user_msg.user_id = user.user_id
    LEFT JOIN group ON user_msg.group_id = group.group_id
    WHERE user.gmt_modified >= date_sub('2018-03-29 09:31:44', INTERVAL 30 SECOND)
    
    • 1
    • 2
    • 3
    • 4
    • 5

    sql-02以用户为驱动表,msg user_id的索引过滤行很好。

    第三部分sql-03如下:

    SELECT user_msg.msg_id AS ‘msg_id’, user_msg.content AS ‘msg_content’, …
    FROM user_msg
    LEFT JOIN user ON user_msg.user_id = user.user_id
    LEFT JOIN group ON user_msg.group_id = group.group_id
    WHERE group.gmt_modified >= date_sub('2018-03-29 09:31:44', INTERVAL 30 SECOND)
    
    • 1
    • 2
    • 3
    • 4
    • 5

    sql-03以group为驱动表,使用gmt_modified索引过滤最新数据。

    总结

    MySQL OR条件优化的常见场景主要有以下情况:

    1,相同列可以使用IN进行代替

    2,不同列及复杂的情况下,可以使用union all进行分离

    3,关联SQL OR条件

    我们需要结合实际场景,分析优化。

    更多技术可以去官网查看https://www.dtstack.com/dtsmart/

    • 全部评论(0)
    • 最新

    信息加载中,请等待

    微信客服(速回)

    微信客服(慢回)



    企业微信客服二维码
    联系我们
    平台客服: 平台QQ客服

    平台电话:400电话迁移中!

    平台邮箱:28292383@qq.com

    工作时间:周一至周五:早10:00 晚:18:00

    营业执照     网站ICP备案:鲁ICP备20027607号-1     鲁公网安备:37068702000078号     增值电信业务经营许可证、在线数据与交易处理业务许可证:鲁B2-20200681      © 2016-2024 站保站  https://www.zhanbaozhan.com/ 版权所有!      平台规范:   关于我们   广告合作   隐私条款   免责声明   法律声明   服务条款   网站地图   平台工单!