【问题标题】:Joining multiple times on the same table for different criteria vs. once on aggregated table针对不同的标准在同一个表上多次加入,而不是在聚合表上加入一次
【发布时间】:2015-11-06 15:41:00
【问题描述】:

我目前有一个视图可以根据相同的条件多次连接一个表,例如:

Select
m.ID,
a.value as value1,
b.value as value2,
c.value as value3,
d.value as value4

from
main_table m
left join other_table a on m.ID = a.ID and a.X = 'this'
left join other_table b on m.ID = b.ID and b.X = 'that'
left join other table c on m.ID = c.ID and c.X = 'third'
left join other table d on m.ID = d.ID and d.X = 'other'

我想知道将四个表合并并聚合它们是否更有效,这样我就可以在一个连接中完成所有操作:

Select
m.ID,
value1,
value2,
value3,
value4

from
main_table m
left join (select ID,
           MAX(case X when 'this' then value end) value1,
           MAX(case X when 'that' then value end) value2,
           MAX(case X when 'third' then value end) value3,
           MAX(case X when 'other' then value end) value4
           from ( 
           select ID,X,value from other_table
           where X = 'this'
           union all
           select ID,X,value from other_table
           where X = 'that'
           union all
           select ID,X,value from other_table
           where X = 'third'
           union all
           select ID,X,value from other_table
           where X = 'other')
           GROUP BY ID) AS A
on A.ID = m.ID

我是在实验之前问的,因为实际上视图比这要复杂得多,并且需要很长时间才能重写,所以我想确保我没有浪费时间。

基本上,我的问题是执行聚合和group by 的成本是否会超过执行这些多个连接的成本。另外,我认为包含此视图包含 许多 个其他联接 (15-20) 的事实是相关的,因此我试图通过以任何方式减少该数量来进行优化。

编辑另外我觉得有必要补充一下,其中涉及链接服务器,这两个表位于不同的数据库上;我尝试减少连接数量的另一个原因。

任何见解或帮助将不胜感激。

提前致谢。

【问题讨论】:

  • 查询是不同的,除非您可以保证在其他表中不超过一个匹配项。另外,“其他表”总是同一张表吗?
  • 我可能会坚持第一个选项。如果您担心性能问题,请确保您在X 上有一个索引。您甚至可以为X 的每个值添加一些过滤索引。
  • @GordonLinoff 怎么样?如果 ID 在另一个表中不存在,我不会得到 NULLvalue 吗?
  • @Samcd 。 . .我措辞不正确。我的意思是不超过一个,至少一个。
  • @GordonLinoff 是的 other_table 始终是同一张表

标签: sql sql-server join optimization sql-server-2008-r2


【解决方案1】:

与大多数性能问题一样,您需要测试系统上数据的不同版本。但是,我认为您想要的聚合查询是:

Select m.ID, value1, value2, value3, value4
from main_table m left join
     (select ID,
             MAX(case X when 'this' then value end) value1,
             MAX(case X when 'that' then value end) value2,
             MAX(case X when 'third' then value end) value3,
             MAX(case X when 'other' then value end) value4
      from other_table
      group by ID
     ) A
     on A.ID = m.ID;

聚合的优点是添加更多的值不会对性能有太大的改变。添加新连接会影响性能,因此在某些时候,聚合可能会优于连接。

【讨论】:

    【解决方案2】:

    根据我的经验,我在特定架构设计中遇到过类似的问题,我们将自定义属性及其值存储在实体的单独表中,并且当我们必须查询实体实例的所有自定义属性数据时我们不得不多次加入同一张桌子。

    我们有效地使用了PIVOT 语法来规避多个连接。在你的情况下,这就像。

    Select
    m.ID,
    [this],[that],[third],[other]
    from
    main_table m
    left join
        (
            select id,[this],[that],[third],[other]
                (select id, X from other_table )s
                    PIVOT
                ( 
                    max(value) 
                        for X in ([this],[that],[third],[other])
                )p 
        )t
    on t.id=m.id
    

    注意:请注意,在我们的案例中,通过避免所有JOINS

    ,这导致了巨大的性能提升

    【讨论】:

    • +1 因为它确实有效,也因为这是我在阅读您的答案后第一次能够使用 PIVOT 功能。但我接受了另一个答案,因为它更接近我一直在使用的答案,并且因为它接受了我在此视图的其他部分需要的多个标准 (MAX(case when X = 'this' AND ...)
    猜你喜欢
    • 2012-05-29
    • 2021-04-01
    • 1970-01-01
    • 2015-04-03
    • 1970-01-01
    • 1970-01-01
    • 2017-01-22
    • 1970-01-01
    • 2015-04-04
    相关资源
    最近更新 更多