前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >技术分享 | 又是一条慢 SQL 改写,拿捏!

技术分享 | 又是一条慢 SQL 改写,拿捏!

作者头像
爱可生开源社区
发布2023-08-18 20:20:25
1910
发布2023-08-18 20:20:25
举报

作者:马文斌

MySQL 爱好者。

本文来源:原创投稿

* 爱可生开源社区出品,原创内容未经授权不得随意使用,转载请联系小编并注明来源。


1背景

开发同学丢了一条 SQL 过来。“马哥,看看这条 SQL 能否优化,业务那边反馈很慢!”看了下执行计划+表结构,索引都没问题。那到底是怎么回事呢?咱们一起来瞧瞧。

2分析原 SQL

代码语言:javascript
复制
explain SELECT
        count(0)
FROM
        invoice_sales_application a
WHERE
        (
                shop_order_id LIKE '23060919546335%'
                OR (
                        EXISTS (
                                SELECT
                                        1
                                FROM
                                        invoice_sales_application_detail b
                                WHERE
                                        a.application_no = b.application_no
                                AND a.invoice_category = b.invoice_category
                                AND b.del_flag = 0
                                AND b.shop_order_id LIKE '23060919546335%'
                        )
                        AND a.is_merge = 1
                )
        )

先来看看这个 SQL 是什么意思:

invoice_sales_application 表中,shop_order_id'23060919546335%'开头,或者存在一个相关的 invoice_sales_application_detail 表中的记录,该记录的 application_noinvoice_categoryinvoice_sales_application 表中的相同,并且 shop_order_id'23060919546335%' 开头,同时 invoice_sales_application 表中的 is_merge 字段为 1

执行计划:all+ref,其中 a 表要扫描 116w 行的数据。

执行计划

执行需要 43s,且有一个全表扫描。

扫描时间

3优化操作

EXISTS 转化成 JOIN 的方式

这里是把 EXISTS 改写成 INNER JOIN 通过索引关键关联,应该会有不错的效果,试试看。

代码语言:javascript
复制
SELECT  count(0)
FROM invoice_sales_application a INNER
JOIN invoice_sales_application_detail b
  ON a.application_no = b.application_no
WHERE ( a.shop_order_id LIKE '23060919546335%'
    OR ( b.shop_order_id LIKE '23060919546335%'
    AND a.is_merge = 1 ) )
    AND a.invoice_category = b.invoice_category
    AND b.del_flag = 0

执行效果

这里虽然转化了 INNER JOIN 的方式,执行计划还是 all+ref ,因为用了 OR 导致 a 表没有用上索引,还是用的全表扫描。没关系,咱们再次进行转化。

OR 改成 UNION

代码语言:javascript
复制
 SELECT count(*)
 FROM invoice_sales_application a
 INNER JOIN invoice_sales_application_detail b ON a.application_no = b.application_no
 AND a.invoice_category = b.invoice_category
 AND b.del_flag = 0
 WHERE a.shop_order_id = '23060919546335'
 AND a.del_flag = 0
 UNION
 SELECT count(*)
 FROM invoice_sales_application a
 INNER JOIN invoice_sales_application_detail b ON a.application_no = b.application_no
 AND a.invoice_category = b.invoice_category
 AND b.del_flag = 0
 WHERE b.shop_order_id = '23060919546335'
 AND a.is_merge = 1
 AND a.del_flag = 0;

在看看执行计划,eq_ref+ref+ref+ref。说明已经优化的很好了,起码没有全表扫描。

执行计划

最后看看结果。

执行计划

这样 SQL 执行很快了,查询时间从 42s 降到 18ms,快了几个数量级。

4小结

1、当 SQL 的主架构中含有 EXISTS 的时候,可以改成 INNER JOIN 的方式,先看看效果。

2、当条件中有 OR 的时候,可以改成 UNION 试试。

本文关键字:#MySQL# #SQL优化#

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2023-07-12,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 爱可生开源社区 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1背景
  • 2分析原 SQL
  • 3优化操作
    • EXISTS 转化成 JOIN 的方式
      • OR 改成 UNION
      • 4小结
      相关产品与服务
      云数据库 MySQL
      腾讯云数据库 MySQL(TencentDB for MySQL)为用户提供安全可靠,性能卓越、易于维护的企业级云数据库服务。其具备6大企业级特性,包括企业级定制内核、企业级高可用、企业级高可靠、企业级安全、企业级扩展以及企业级智能运维。通过使用腾讯云数据库 MySQL,可实现分钟级别的数据库部署、弹性扩展以及全自动化的运维管理,不仅经济实惠,而且稳定可靠,易于运维。
      领券
      问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档