Redian新闻
>
又是一条慢SQL改写,拿捏!

又是一条慢SQL改写,拿捏!

公众号新闻

作者:马文斌

MySQL 爱好者。

爱可生开源社区出品


1背景

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

2分析原 SQL

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 通过索引关键关联,应该会有不错的效果,试试看。

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

 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 试试。

往期推荐



CentOS 项目宣称 “向所有人开放”
微软推出新的默认字体Aptos替代Calibri,网友:I、l终于能分清了
微软:Rust安全可靠,Windows内核加大力度使用



这里有最新开源资讯、软件更新、技术干货等内容

点这里 ↓↓↓ 记得 关注✔ 标星⭐ 哦


微信扫码关注该文公众号作者

戳这里提交新闻线索和高质量文章给我们。
相关阅读
硬核观察 #1037 PostgreSQL 超过 MySQL 成为开发者首选数据库SpringBoot 2 种方式快速实现分库分表,轻松拿捏!必囤好课|三周带你从0到1掌握Python, SQL, Excel等核心技能,课程免费无限次回放!这将是一场灾难?37年历史的PostgreSQL数据库将进行重大架构变更小说连载 《四维空间的魔鬼与人类起源》 01大数据SQL数据倾斜与数据膨胀的优化与经验总结华为回应车BU独立运营,小米大模型首次被曝光,马斯克考虑取消与小扎的笼中斗,LOL改进投降机制,这就是今天的其他大新闻!MySQL 被 PG 干翻了。。“软肋”再度被拿捏!他们开始入侵校园,真的太可怕了当LLM遇到Database:阿里达摩院联合HKU推出Text-to-SQL新基准​从MySQL到OBOracle:如何处理自增列?City Glamping总攻略|又是一年露营季,又是一场全新的旅行小说连载 《四维空间的魔鬼与人类起源》-- 03用雪花 id 和 uuid 做 MySQL 主键,被领导怼了奇怪的SQL问题+1PHP程序员薪资竟然垫底、PG取代MySQL成为最流行数据库MySQL 巨坑:永远不要在 MySQL 中使用 UTF-8!!PostgreSQL正面临抉择面试数据岗时,怎么把自己的SQL技能展现出来?一文走进SQL编译-语义解析ClickHouse和PostgreSQL:“数据天堂”中的好搭档回。首Offspring of Spirit小说连载 《四维空间的魔鬼与人类起源》-- 02MySQL高级进阶:索引优化用户量比肩京东阿里,又是一条大鱼?FlinkSQL 数据权限之数据脱敏解决方案高效方案:30万条数据插入 MySQL 仅需13秒MySQL 单表数据最大不要超过多少行?为什么?开源产品测评之SQL上线能力SQL骚操作,一条SQL 统计近 7天、30天、全部的订单量MyBatis 动态 SQL 最全教程,这样写 SQL 太爽了!你踩不死的蟑螂,小小的它却轻松拿捏!好上镜的证件照妆!教科书式解析,3 种风格全拿捏!线上 MySQL 的自增 id 用尽怎么办?
logo
联系我们隐私协议©2024 redian.news
Redian新闻
Redian.news刊载任何文章,不代表同意其说法或描述,仅为提供更多信息,也不构成任何建议。文章信息的合法性及真实性由其作者负责,与Redian.news及其运营公司无关。欢迎投稿,如发现稿件侵权,或作者不愿在本网发表文章,请版权拥有者通知本网处理。