在select中优化派生表

时间:2018-04-14 19:57:09

标签: mysql performance query-optimization

我有sql查询:

SELECT tsc.Id
FROM TEST.Services tsc, 
( 
    select * from DICT.Change sp 

) spc
where tsc.serviceId = spc.service_id 
and tsc.PlanId = if(spc.plan_id = -1, tsc.PlanId, spc.plan_id) 
and tsc.startDate > GREATEST(spc.StartTime, spc.startDate) 
group by tsc.Id; 

此查询非常非常慢。

说明: enter image description here 这可以优化吗?如何将这个子查询重写为另一个?

1 个答案:

答案 0 :(得分:1)

这个查询有什么意义?为什么CROSS JOIN操作?为什么我们需要从id表返回Services列的多个副本?我们在回收数百万行时做了什么?

缺少规范,结果集的实际要求集,我们只是猜测它。

回答你的问题:

是的,可以通过将查询重写为实际需要的结果集来“优化”查询,并且比问题中的怪异可疑SQL更有效率。

一些建议:抛弃连接操作的旧式逗号语法,而是使用JOIN关键字。

没有连接谓词,它是一个“交叉”连接。从一侧匹配的每一行与右侧的每一行匹配。)我建议包含 CROSS 关键字,以表明未来读者缺少 {{1 }} 子句(或者,ON子句中的连接谓词)是有意的,而不是疏忽。

除非有特定原因,否则我也会避免使用内联视图。

<强>更新

问题中的查询已更新为包含一些谓词。根据更新的查询,我会这样写:

WHERE

通过查看SELECT tsc.id FROM TEST.Services tsc JOIN DICT.Change spc ON tsc.serviceid = spc.service_id AND tsc.startdate > spc.starttime AND tsc.startdate > spc.starttdate AND ( tsc.planid = spc.plan_id OR ( tsc.planid IS NOT NULL AND spc.plan_id = -1 ) ) 的输出来确保查询正在使用合适的索引,以查看执行计划,特别是正在使用的索引。

一些注意事项:

如果EXPLAIN中有多个行与spc中的一行“匹配”,则查询将返回tsc的重复值。 (目前尚不清楚为什么或者我们是否需要返回重复值。如果我们需要计算每个tsc.id的副本数量,我们可以在查询中执行此操作,返回tsc,id的不同值以及如果我们不需要重复,我们可以只返回一个不同的列表。

如果任何参数为null,

tsc.id函数将返回GREATEST。如果我们需要的条件是“NULL”,我们可以指定“a > GREATEST(b,c)”。

另外,这个条件:

a > b AND a > c

可以重写以返回等效结果(我对实际规范有疑问,以及这个原始条件是否真正满足了这一点。没有示例数据和预期输出的样本,我们必须依赖SQL作为规范,所以我们在重写时尊重它。)

如果我们不需要返回tsc.PlanId = if(spc.plan_id = -1, tsc.PlanId, spc.plan_id) 的重复值,假设tsc.id中的id是唯一的,我们也可以写

TEST.Services
相关问题