MySQL性能优化(八)exists子查询优化一例

俊达3年前技术文章985


一个例子

SELECT u.id userId,       u.mobile,       u.created_date createdDate 
FROM `user` u
    LEFT JOIN user_cash_detail ucd ON u.id= ucd.user_id
WHERE 1= 1
AND EXISTS( SELECT 1 FROM borrow b WHERE b.user_id= u.id AND b.borrow_no LIKE '202001011212XXX%') 
ORDER BY u.id limit 13

这个查询需要执行120秒,


执行计划:

8-1.png


从执行计划中来看都有这良好的索引,而且需要扫描的rows 也很少,此条SQL性能应该比较好,为什么会执行需要120s 的时间呢?

此时需要了解下exists查询的执行过程:先执行主查询,然后用主查询的结果,检查exists子句中的子查询是否能匹配。

如果主表返回的纪录数比较大,exists 运行的次数就会大,导致整个查询的运行时间长。


在上面这个例子中,exists子查询中有一个b.borrow_no的条件,看起来过滤性比较高,可以尝试对SQL进行改写:

SELECT distinct u.id userId,       u.mobile,       u.created_date createdDate  
FROM borrow b 
join `user` u on b.user_id= u.id 
where b.borrow_no LIKE '202001011212XXX%' order by u.id limit 13


执行计划:

8-2.png


将exists子查询改写为常规的表关联,有几个地方需要注意:

1、原始SQL中并没有使用到user_cash_detail表,可以将left join去掉。

2、Exists 改成join后,由于borrow表user_id不唯一,SQL改写后可能会有重复数据出现,需要添加distinct,


SQL改写后,执行时间从120秒提升到3毫秒。


总结

SQL优化的一个基本思想是尽早过滤尽可能多的数据。这本例中,先执行exists中的子查询可以提前过滤掉大量数据。当然有时候需要对SQL进行一些改写。

相关文章

数据库性能大揭秘:玩转MySQL监控指标状态变量

前言在本文中,我们将深入探讨MySQL数据库的性能监控世界。通过了解并应用一系列常用的监控指标,我们能够更精准地把握数据库的运行状况。这些指标,通常以状态变量(status variables)的形式...

LINUX 安全运维-OpenSSH安全

LINUX 安全运维-OpenSSH安全

SSH 是建立在应用层基础上的安全协议,是目前较可靠,专为远程登录会话和其他网络服务提供安全性的协议。利用 SSH协议可以有效防止远程管理过程中的信息泄露问题。SSH最初是UNIX系统上的一...

ES基础知识介绍

ES 核心概念ES 是使用 Java 编写的一种开源搜索引擎,它在内部使用 Lucene 做索引与搜索,通过对 Lucene 的封装,隐藏了 Lucene 的复杂性,取而代之的提供一套简单一致的 RE...

kubernetes调度策略

1、背景在 Kubernetes 中,调度 (scheduling) 指的是确保 Pod 匹配到合适的节点,以便 kubelet 能够运行它们。调度的工作由调度器和控制器协调完成。调度器通过 Kube...

HDFS元数据损坏恢复方法

HDFS元数据损坏恢复方法

HDFS JournalNode 编辑目录(dfs.journalnode.edits.dir)下数据损坏(单节点损坏或所有节点数据损坏),如何恢复 HDFS?单节点损坏a)  &...

数据湖技术之iceberg(九)Spark与Iceberg整合写操作

数据湖技术之iceberg(九)Spark与Iceberg整合写操作

1. INSERT INTO"insert into"是向Iceberg表中插入数据,有两种语法形式:"INSERT INTO tbl VALUES (1,"z...

发表评论    

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。