现象
有这么一张表:
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。
优化
优化的第一步就是看执行计划:

挺可怕的一个执行计划,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;
这个执行计划就变成了这样:

注意扫描行数,不过102行,而且type的类型也是很优秀的,至于效果,这是优化前:

这是优化后:

高下立判。
结语
其实子查询是一种自然的想法的具体实现,在非DBA写的SQL中很常见,因为逻辑上是无懈可击的。但是DBA至少应该具有集合计算的基本素质,在考虑数据库关联查询的时候首先要想到集合运算,然后是关系代数理论。
DBA确实不是一个简单的工作,数学也不能差。
网友评论