在select中优化派生表

yebdmbv4  于 2021-06-21  发布在  Mysql
关注(0)|答案(1)|浏览(304)

我有 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;

这个查询非常非常慢。
解释:

这能优化吗?如何为另一个子查询重写此子查询?

gopyfrb3

gopyfrb31#

这个问题有什么意义?为什么要交叉连接操作?为什么我们需要返回多个副本 id 列自 Services table?我们怎么处理被退回的数百万行呢?
如果没有一个规范,一组实际的结果集需求,我们只是在猜测。
回答您的问题:
是的,通过将查询重写为实际需要的结果集,可以对查询进行“优化”,并且比问题中可怕的sql更有效。
一些建议:抛弃join操作的老式逗号语法,使用 JOIN 改为关键字。
如果没有连接 predicate ,则是“交叉”连接。从一侧匹配到右侧匹配)我建议包括 CROSS 关键字作为对未来读者的指示 ON 子句中的连接 predicate WHERE 是故意的,而不是疏忽。
我也会避免使用内联视图,除非有特定的原因。
更新
问题中的查询将更新为包含一些 predicate 。根据更新后的查询,我会这样写:

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 如果任何参数为null。如果我们需要的条件是 a > GREATEST(b,c) ,我们可以指定 a > b AND a > c ".
此外,这种情况:

tsc.PlanId = if(spc.plan_id = -1, tsc.PlanId, spc.plan_id)

可以重写以返回一个等价的结果(我怀疑实际的规范,以及这个原始条件是否充分满足这个条件)。没有示例数据和预期输出的示例,我们只能依赖sql作为规范,因此我们在重写时尊重这一点。)
如果我们不需要返回 tsc.id ,假设 id 是独一无二的 TEST.Services ,我们也可以写

SELECT tsc.id
  FROM TEST.Services tsc
 WHERE EXISTS 
       ( SELECT 1
           FROM DICT.Change spc
             ON spc.service_id = tsc.serviceid
            AND spc.starttime  < tsc.startdate
            AND spc.starttdate < tsc.startdate
            AND ( ( spc.plan_id = tsc.planid )
               OR ( spc.plan_id = -1 AND tsc.planid IS NOT NULL )
                )
       )

相关问题