我有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;
此查询非常非常慢。
答案 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
的不同值以及如果我们不需要重复,我们可以只返回一个不同的列表。
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