使用多个联接优化查询

时间:2014-09-15 10:38:33

标签: mysql sql sql-server sql-server-2008 join

这是我当前的查询:

select i.id, i.alder, i.kon, i.artal, i.vecka, s.fraga, s.varumarke, 
       part1.JokerinText, part2.LotonText, part3.VikingText, 
       part4.VedonlyönninText, part5.KenonText 

from intervjuperson i

inner join svar s on s.intervjuperson = i.id

left join (select s2.text as LotonText, s2.intervjuperson 
         from svar s2 where s2.fraga = 97607) as part2 on part2.intervjuperson = i.id

left join (select s2.text as VikingText, s2.intervjuperson 
         from svar s2 where s2.fraga = 97608) as part3 on part3.intervjuperson = i.id

left join (select s2.text as jokerinText, s2.intervjuperson 
         from svar s2 where s2.fraga = 97609) as part1 on part1.intervjuperson = i.id

left join (select s2.text as VedonlyönninText, s2.intervjuperson 
         from svar s2 where s2.fraga = 97610) as part4 on part4.intervjuperson = i.id

left join (select s2.text as KenonText, s2.intervjuperson 
         from svar s2 where s2.fraga = 97611) as part5 on part5.intervjuperson = i.id

where s.fraga in (97606) and i.artal > 2010

如何优化此查询以便花费几秒钟,因为目前需要2分钟?

2 个答案:

答案 0 :(得分:4)

首先检查表svar上是否缺少索引。

应该由fragaintervjuperson字段编制索引。如果是SQL Server,请选中"显示估计的执行计划"在SQL Management Studio中打开此查询 - 它将向您显示,哪些索引可以改进您的查询。理想的是由fragaintervjuperson列组成的一个索引。

您的查询最终可能会被重写。

select i.id, i.alder, i.kon, i.artal, i.vecka, s.fraga, s.varumarke, 
       part1.text as JokerinText, part2.text as LotonText, part3.text as VikingText, 
       part4.text as VedonlyönninText, part5.text as KenonText 
from intervjuperson i
inner join svar s on s.intervjuperson = i.id
left join svar as part2 on part2.intervjuperson = i.id AND part2.fraga = 97607
left join svar as part3 on part3.intervjuperson = i.id AND part3.fraga = 97608
left join svar as part1 on part1.intervjuperson = i.id AND part1.fraga = 97609
left join svar as part4 on part4.intervjuperson = i.id AND part4.fraga = 97610
left join svar as part5 on part5.intervjuperson = i.id AND part5.fraga = 97611
where s.fraga in (97606) and i.artal > 2010

答案 1 :(得分:1)

我认为id是表intervjuperson的主键,列intervjuperson加fraga构成表svar的主键,所以你的所有左连接为每个intervjuperson提供一个或零记录?

然后你可以只使用一次外连接,并在SELECT子句中使用CASE结构来获取你感兴趣的值。

select 
  i.id, i.alder, i.kon, i.artal, i.vecka, 
  s.fraga, s.varumarke,
  case when parts.fraga = 97609 then parts.text end as JokerinText, 
  case when parts.fraga = 97607 then parts.text end as LotonText, 
  case when parts.fraga = 97608 then parts.text end as VikingText, 
  case when parts.fraga = 97610 then parts.text end as VedonlyönninText, 
  case when parts.fraga = 97611 then parts.text end as KenonText 
from intervjuperson i
inner join svar s on s.intervjuperson = i.id
left join svar as parts on parts.intervjuperson = i.id
where s.fraga in (97606) and i.artal > 2010
group by i.id, s.fraga;

您在MySQL和SQL Server上标记了您的问题。以上查询是针对MySQL的。在其他dbms中,SELECT子句中的每个列都必须是聚合或GROUP BY子句的一部分。对于这样的dbms,您必须将i.alder更改为MIN(i.alder)或MAX,或者在GROUP BY子句中使用i.alder。 CASE结构也必须聚合:

select 
  i.id, min(i.alder) as alder, min(i.kon) as kon, min(i.artal) as artal, min(i.vecka) as vecka, 
  s.fraga, min(s.varumarke) as varumarke,
  min(case when parts.fraga = 97609 then parts.text end) as JokerinText, 
  min(case when parts.fraga = 97607 then parts.text end) as LotonText, 
  min(case when parts.fraga = 97608 then parts.text end) as VikingText, 
  min(case when parts.fraga = 97610 then parts.text end) as VedonlyönninText, 
  min(case when parts.fraga = 97611 then parts.text end) as KenonText 
from intervjuperson i
inner join svar s on s.intervjuperson = i.id
left join svar as parts on parts.intervjuperson = i.id
where s.fraga in (97606) and i.artal > 2010
group by i.id, s.fraga;

编辑:我刚注意到:出于性能原因,您可能希望将and parts.fraga in (97607,97608,97609,97610,97611)添加到左连接的ON子句中。这不会改变结果,但可能会加快连接速度。