简化复杂选择查询的技巧

时间:2015-04-05 01:08:59

标签: sql sql-server tsql select

最近,我注意到我的一个存储过程花费了很长时间才能运行。

我认为我的问题有点过于具体而无法正确提出,所以我认为我要求解决我的问题以及如何简化复杂陈述的建议。

我有一个"结果"我的SSMS数据库中的表。我有的选择查询会根据结果生成排名。

排名是根据作为参数提供的日期生成的,并根据过去四年的结果计算。

去年的结果得到100%的积分,一年到两年前得到75%,2到3年前得到50%,3到4年前得到25%。< / p>

我还得到另一个名为&#34; Rank Change&#34;的计算列,这是自提供日期之前的最后一个结果以来的排名变化。

查询如下。

由于这是一个复杂的查询,可能很难简化,如果可能,您会如何简化此查询?

你使用什么技术来简化像这样的查询,如果有的话?

IF (@Date < '2000-01-01')
BEGIN
    SET @Date = '2000-01-01'
END

DECLARE @LatestContestDate DATE

SET @LatestContestDate = ( SELECT TOP 1 Date
                           FROM     Results
                           WHERE    Date < @Date
                           ORDER BY Date DESC
                         )

SET @LatestContestDate = DATEADD(DD, -1, @LatestContestDate)

SELECT  Band.Name ,
        Area.Name ,
        ( ISNULL(( SELECT   SUM(R2.Points) /*Calculates points*/
                   FROM     Results R2
                   WHERE    R2.Date > DATEADD(YY, -1, @Date)
                            AND R2.Date < DATEADD(DD, 1, @Date)
                            AND R2.BandID = R1.BandID
                 ), 0)
          + ISNULL(( SELECT ( SUM(R2.Points) * 0.75 )
                     FROM   Results R2
                     WHERE  R2.Date < DATEADD(YY, -1, @Date)
                            AND R2.Date > DATEADD(YY, -2, @Date)
                            AND R2.BandID = R1.BandID
                   ), 0)
          + ISNULL(( SELECT ( SUM(R2.Points) * 0.5 )
                     FROM   Results R2
                     WHERE  R2.Date < DATEADD(YY, -2, @Date)
                            AND R2.Date > DATEADD(YY, -3, @Date)
                            AND R2.BandID = R1.BandID
                   ), 0)
          + ISNULL(( SELECT ( SUM(R2.Points) * 0.25 )
                     FROM   Results R2
                     WHERE  R2.Date < DATEADD(YY, -3, @Date)
                            AND R2.Date > DATEADD(YY, -4, @Date)
                            AND R2.BandID = R1.BandID
                   ), 0) ) AS PointsTotal , /*Below Calculates rank change*/
        ( ( ROW_NUMBER() OVER ( ORDER BY ( ISNULL(( SELECT
                                                          SUM(R2.Points)
                                                    FROM  Results R2
                                                    WHERE R2.Date > DATEADD(YY,
                                                          -1,
                                                          @LatestContestDate)
                                                          AND R2.Date < DATEADD(DD,
                                                          1,
                                                          @LatestContestDate)
                                                          AND R2.BandID = R1.BandID
                                                  ), 0)
                                           + ISNULL(( SELECT
                                                          ( SUM(R2.Points)
                                                          * 0.75 )
                                                      FROM
                                                          Results R2
                                                      WHERE
                                                          R2.Date < DATEADD(YY,
                                                          -1,
                                                          @LatestContestDate)
                                                          AND R2.Date > DATEADD(YY,
                                                          -2,
                                                          @LatestContestDate)
                                                          AND R2.BandID = R1.BandID
                                                    ), 0)
                                           + ISNULL(( SELECT
                                                          ( SUM(R2.Points)
                                                          * 0.5 )
                                                      FROM
                                                          Results R2
                                                      WHERE
                                                          R2.Date < DATEADD(YY,
                                                          -2,
                                                          @LatestContestDate)
                                                          AND R2.Date > DATEADD(YY,
                                                          -3,
                                                          @LatestContestDate)
                                                          AND R2.BandID = R1.BandID
                                                    ), 0)
                                           + ISNULL(( SELECT
                                                          ( SUM(R2.Points)
                                                          * 0.25 )
                                                      FROM
                                                          Results R2
                                                      WHERE
                                                          R2.Date < DATEADD(YY,
                                                          -3,
                                                          @LatestContestDate)
                                                          AND R2.Date > DATEADD(YY,
                                                          -4,
                                                          @LatestContestDate)
                                                          AND R2.BandID = R1.BandID
                                                    ), 0) ) DESC ) )
          - ( ROW_NUMBER() OVER ( ORDER BY ( ISNULL(( SELECT
                                                          SUM(R2.Points)
                                                      FROM
                                                          Results R2
                                                      WHERE
                                                          R2.Date > DATEADD(YY,
                                                          -1, @Date)
                                                          AND R2.Date < DATEADD(DD,
                                                          1, @Date)
                                                          AND R2.BandID = R1.BandID
                                                    ), 0)
                                             + ISNULL(( SELECT
                                                          ( SUM(R2.Points)
                                                          * 0.75 )
                                                        FROM
                                                          Results R2
                                                        WHERE
                                                          R2.Date < DATEADD(YY,
                                                          -1, @Date)
                                                          AND R2.Date > DATEADD(YY,
                                                          -2, @Date)
                                                          AND R2.BandID = R1.BandID
                                                      ), 0)
                                             + ISNULL(( SELECT
                                                          ( SUM(R2.Points)
                                                          * 0.5 )
                                                        FROM
                                                          Results R2
                                                        WHERE
                                                          R2.Date < DATEADD(YY,
                                                          -2, @Date)
                                                          AND R2.Date > DATEADD(YY,
                                                          -3, @Date)
                                                          AND R2.BandID = R1.BandID
                                                      ), 0)
                                             + ISNULL(( SELECT
                                                          ( SUM(R2.Points)
                                                          * 0.25 )
                                                        FROM
                                                          Results R2
                                                        WHERE
                                                          R2.Date < DATEADD(YY,
                                                          -3, @Date)
                                                          AND R2.Date > DATEADD(YY,
                                                          -4, @Date)
                                                          AND R2.BandID = R1.BandID
                                                      ), 0) ) DESC ) ) ) AS RankChange
FROM    Results R1
        INNER JOIN Band ON R1.BandID = Band.ID
        INNER JOIN Area ON Band.AreaID = Area.ID
WHERE   ( ISNULL(( SELECT   SUM(R2.Points)
                   FROM     Results R2
                   WHERE    R2.Date > DATEADD(YY, -1, @Date)
                            AND R2.Date < DATEADD(DD, 1, @Date)
                            AND R2.BandID = R1.BandID
                 ), 0)
          + ISNULL(( SELECT ( SUM(R2.Points) * 0.75 )
                     FROM   Results R2
                     WHERE  R2.Date < DATEADD(YY, -1, @Date)
                            AND R2.Date > DATEADD(YY, -2, @Date)
                            AND R2.BandID = R1.BandID
                   ), 0)
          + ISNULL(( SELECT ( SUM(R2.Points) * 0.5 )
                     FROM   Results R2
                     WHERE  R2.Date < DATEADD(YY, -2, @Date)
                            AND R2.Date > DATEADD(YY, -3, @Date)
                            AND R2.BandID = R1.BandID
                   ), 0)
          + ISNULL(( SELECT ( SUM(R2.Points) * 0.25 )
                     FROM   Results R2
                     WHERE  R2.Date < DATEADD(YY, -3, @Date)
                            AND R2.Date > DATEADD(YY, -4, @Date)
                            AND R2.BandID = R1.BandID
                   ), 0) ) > 0
GROUP BY    Band.Name ,
    Area.Name,
    BandID
ORDER BY PointsTotal DESC

2 个答案:

答案 0 :(得分:3)

使用条件聚合进行点计算。类似的东西:

select (sum(case when r2.Date > DATEADD(year, -1, @Date) and r2.Date < DATEADD(day, 1, @Date)
                 then r2.points else 0
            end) +
        sum(case when r2.Date < DATEADD(year, -1, @Date) and r2.Date > DATEADD(year, -2, @Date)
                 then r2.points else 0
            end) * 0.75 +
       . . .
      )
from results r2
where r2.BandID = r1.BandID and
      r2.Date >= dateadd(year, -4, @Date)

然后将其放入子查询中,以及用于row_number的类似查询的类似表达式。然后引用SELECTROW_NUMBER()WHERE中子查询的表达式。这样可以将子查询的数量从16减少到1或2。

您可以使用results(BandId, Date)上的索引对此进行优化。

在SQL Server 2012+中,您可以使用累积总和来执行所需的操作。

答案 1 :(得分:0)

很难确切地说明如何在不知道底层架构和表格如何的情况下修改select语句。那就是说我会先看看sql server management studio中的execution plan,然后看看查询瓶颈是什么:缺少索引,缺点,IO,缺少统计信息等。

这是一个非常好的link,可以让您开始快速调整查询的性能: