【问题标题】:Optimizing a query with multiple joins使用多个连接优化查询
【发布时间】:2023-03-12 02:38:01
【问题描述】:

这是我当前的查询:

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 分钟?

【问题讨论】:

  • 这是 MySql 还是 SQL Server?
  • 能否格式化您的代码?另外,您定义的索引是什么?你检查瓶颈的执行计划了吗?
  • 尝试删除子选择 - 您可以添加子选择s where clauses to the LEFT JOINs 子句。这可能会有所帮助,这取决于您拥有哪些索引以及表的大小以及优化器将如何处理。
  • 如果您愿意,请考虑遵循以下简单的两步操作: 1. 如果您还没有这样做,请提供适当的 DDL(和/或 sqlfiddle),以便我们可以更轻松地复制问题。 2. 如果您尚未这样做,请提供与步骤 1 中提供的信息相对应的所需结果集。

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


【解决方案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 子句中。这不会改变结果,但可能会加快连接速度。

【讨论】:

    【解决方案2】:

    首先检查表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
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-12-05
      • 1970-01-01
      • 2020-04-30
      • 2012-02-15
      • 1970-01-01
      • 2020-01-02
      相关资源
      最近更新 更多