【问题标题】:SQL - Join two queries together efficientlySQL - 有效地将两个查询连接在一起
【发布时间】:2013-01-24 19:01:09
【问题描述】:

我有两个查询不同表并返回相似字段的 SQL 查询:

User - Role - Category - Points

User - Role - Category - Target

我的查询如下所示:

select
    acs.UserID,
    acs.RoleID,
    acs.CategoryID,
    sum(acs.Points)
from acs

select
    tb.UserID,
    tb.RoleID,
    tb.CategoryID,
    sum(
        (
            (DATEDIFF(dd, (case when @start >= tb.StartDate then @start else tb.StartDate end), (case when @end <= tb.EndDate then @end else tb.EndDate end)) + 1) 
        ) * tb.dailyMed
    ) as Target
from tb

我想要的结果是这样的:

User - Role - Category - Points - Target

每个单独的查询运行时间不到 1 秒,但是当我尝试使用内部连接将它们组合起来时,运行时间超过 3 分钟。

我希望有一种更有效的方法,但我似乎找不到。

*编辑 我的内部连接看起来像这样

select
    acs.UserID,
    acs.RoleID,
    acs.CategoryID,
    sum(acs.Points),
    t.Target
from
    dbo.ActualCacheSale acs
        inner join
            (select
                tb.UserID,
                tb.RoleID,
                tb.CategoryID,
                sum(
                    (
                        (DATEDIFF(dd, (case when @start >= tb.StartDate then @start else tb.StartDate end), (case when @end <= tb.EndDate then @end else tb.EndDate end)) + 1)
                    ) * tb.dailyMed
                ) as Target
            from
                dbo.TargetBucket tb
            ) t on
                t.UserID = acs.UserID and
                t.RoleID = acs.RoleID and
                t.CategoryID = acs.CategoryID

【问题讨论】:

  • 向我们展示您的内部连接查询
  • 您能出示您的 INNER JOIN 语句吗?
  • 您确定在使用 SUM 函数时不需要 GROUP BY 子句吗?
  • 它们在那里,我只是没有将它们包含在我的示例代码中,很抱歉造成混乱

标签: sql sql-server


【解决方案1】:

试试

select
aa.UserId,
aa.Roleid,
aa.CategoryId
Sum(aa.Points) as Points,
Sum(aa.Target) as Target
from
(
select
    acs.UserID,
    acs.RoleID,
    acs.CategoryID,
    sum(acs.Points) as Points
    null as target
from acs

union all

select
    tb.UserID,
    tb.RoleID,
    tb.CategoryID,
    0 as points
    sum(
        (
        (DATEDIFF(dd, (case when @start >= tb.StartDate then @start else tb.StartDatee end),     
    (case when @end <= tb.EndDate then @end else tb.EndDate end)) + 1) 
    ) * tb.dailyMed
    ) as Target
from tb) as aa
group by
aa.UserId,
aa.Roleid,
aa.CategoryId

【讨论】:

  • union + group by 是一种小技巧,多年来对我很有效。当然,在特定情况下。我建议这样做是因为您说每个单独的查询都很快。
  • 我现在已经将联合查询加入到多个表中,它仍然是一个 3 秒的查询。再次感谢
【解决方案2】:

也许我遗漏了一些东西,但我不确定您如何在不分组为聚合的情况下获得总和。无论如何,这是我的看法 - 希望我没有错过任何东西:

SELECT  P.UserID ,
        P.RoleID ,
        P.CategoryID ,
        P.Points ,
        T.Target
FROM    ( SELECT    acs.UserID ,
                    acs.RoleID ,
                    acs.CategoryID ,
                    SUM(acs.Points) Points
          FROM      acs
          GROUP BY  acs.UserID ,
                    acs.RoleID ,
                    acs.CategoryID
        ) P
        CROSS APPLY ( SELECT    tb.UserID ,
                                tb.RoleID ,
                                tb.CategoryID ,
                                SUM(( (DATEDIFF(dd, ( CASE WHEN @start >= tb.StartDate THEN @start
                                                           ELSE tb.StartDate
                                                      END ), ( CASE WHEN @end <= tb.EndDate THEN @end
                                                                    ELSE tb.EndDate
                                                               END )) + 1) ) * tb.dailyMed) AS Target
                      FROM      TB
                      WHERE     TB.UserID = P.UserID
                                AND TB.RoleID = P.RoleID
                                AND TB.CategoryID = P.CategoryID
                      GROUP BY  tb.UserID ,
                                tb.RoleID ,
                                tb.CategoryID
                    ) T

【讨论】:

  • 抱歉,我的查询中有 group by 子句。我会试一试。谢谢
  • 这可行,但仍需要两分钟才能完成。感谢您的帮助。
  • 如果你看一下执行计划,它是否建议任何额外的索引?
【解决方案3】:

您可以发布您用于内部联接的查询吗?通常,如果连接列上有有用的索引,则查询应该执行良好。

如果没有,一个不错的选择是创建两个临时表,其中 1 个用于存储每个查询的结果。然后在连接列的临时表上创建索引。使用临时表运行最终查询。

【讨论】:

  • -1 这真的只是猜测。第一部分应该是评论。
  • @Jacco 并不是真的在猜测,创建或使用索引可能是这里的正确答案。我同意第一部分应该是评论。 SQLSuperGuru,您能否将您的答案格式化好一点并将您的问题移到评论中?
  • 数据库已正确索引,我最初的解决方案是使用临时表,但是这个解决方案比我现在的慢得多。
猜你喜欢
  • 1970-01-01
  • 2015-10-08
  • 1970-01-01
  • 1970-01-01
  • 2017-02-24
  • 2017-06-13
  • 1970-01-01
  • 1970-01-01
  • 2016-05-27
相关资源
最近更新 更多