现象
有这么一张表:
create table test
(
nodeId int,
flowId int,
other varchar(10),
primary key (nodeid),
key idx1 (flowId, nodeId)
)
现在执行这样一个SQL:
select nodeId, flowId from test
where nodeId in (
select max(nodeId)
from test
where flowId in (...) group by flowId
)
这个SQL看起来就很难看,而且不易理解。这个表的记录大概是100万条,这个SQL执行时间超过600ms。
优化
优化的第一步就是看执行计划:
![image.png](https://img.haomeiwen.com/i2921521/5c18cce8dbf2296c.png&originHeight=115&originWidth=1480&size=12179&status=done&width=746?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
挺可怕的一个执行计划,id=1的表,即外层表竟然进行一次索引全扫描,这个等同于全表扫描了。
在这里我要说一句话,这句话在大部分条件下是成立的:
关系型数据库,怕的不是关联
那么我们改造一下这个SQL,将它改成一个关联的写法:
select a.flowId, a.nodeId
from test a
inner join
(select max(nodeId) from test where flowId in (...) group by flowId) b
on a.nodeId = b.nodeId;
这个执行计划就变成了这样:
![image.png](https://img.haomeiwen.com/i2921521/7e5fe75932c80c79.png&originHeight=129&originWidth=1527&size=12895&status=done&width=746?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
注意扫描行数,不过102行,而且type的类型也是很优秀的,至于效果,这是优化前:
![image.png](https://img.haomeiwen.com/i2921521/ba65b565d2a4acab.png&originHeight=28&originWidth=210&size=756&status=done&width=210?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
这是优化后:
![image.png](https://img.haomeiwen.com/i2921521/faccddb502e7608b.png&originHeight=50&originWidth=222&size=1046&status=done&width=222?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
高下立判。
结语
其实子查询是一种自然的想法的具体实现,在非DBA写的SQL中很常见,因为逻辑上是无懈可击的。但是DBA至少应该具有集合计算的基本素质,在考虑数据库关联查询的时候首先要想到集合运算,然后是关系代数理论。
DBA确实不是一个简单的工作,数学也不能差。
网友评论