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

俊达2年前技术文章838


一个例子

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进行一些改写。

相关文章

linux开启Firewall白名单限制ip访问

linux开启Firewall白名单限制ip访问

1、Firewalld是否启动成功systemctl start firewalld && systemctl enable firewalld 1 2、开启规则需求:客户由...

shell脚本-expect

shell脚本-expect

一、概述       Expect是建立在tcl基础上的一个工具,Expect 是用来进行自动化控制和测试的工具。主要解决shell脚本中不可交互的问题。       在一些需要交互输入指令的场景下,...

CDP实操--配置KNOX SSO(五)

CDP实操--配置KNOX SSO(五)

1.1配置Atlas的SSO身份验证在Knox SSO的topology里配置Knox与LDAP集成认证如下,并重启Knox服务role=authenticationauthentication.na...

Trino部署

安装前准备1.1. 创建用户和用户组groupadd trinouseradd -g hadoop trino1.2. 配置环境变量1.2.1. 配置系统环境变量/etc/profileexport...

Go 日志处理

Go 日志处理

1、背景日志文件一般用于记录操作系统或其他软件运行时发生的事件,或通信软件不同用户之间的消息。如果有一些问题需要对程序进行调试或故障排查时,日志是必不可少的,这是我们分析程序问题常用的手段。2、操作前...

MySQL 官方高可用方案:Innodb ReplicaSet

MySQL 官方高可用方案:Innodb ReplicaSet

说明MySQL Innodb ReplicaSet 是 MySQL 团队在 2020 年推出的一款产品,用来帮助用户快速部署和管理主从复制,在数据库层仍然使用的是主从复制技术。ReplicaSet 主...

发表评论    

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