SORT操作的瓶颈

时间:2016-12-19 10:17:13

标签: sql sql-server query-performance sql-server-2016

我有以下查询,它证明非常昂贵,需要6-8秒才能执行。查看执行计划,SORT操作的成本为79%。我可以在这里得到任何改进吗?

IMG

    SELECT
        A.StageName,
        C.Month,
        C.MonthName as Label,
        C.Year,
        isnull(A.Average,0) as Data
    FROM
    (   
        SELECT 
            S.StageName,
            MONTH(TimeIn) as MonthNumber, 
            DATENAME(MONTH,TimeIn) as Month, 
            YEAR(TimeIn) as Year, 
            ISNULL(AVG(DATEDIFF(mi,TimeIn,isnull(TimeOut,@TodayDate))),0) as Average
        FROM
            VisitMovement VM
        INNER JOIN Stage S on
            VM.StageID = S.StageID
        WHERE 
            (VM.TimeIn >= @StartDate AND 
            VM.TimeIn  < DATEADD (d,1,@EndDate)) AND
            (VM.TimeOut < DATEADD (d,1,@EndDate) OR VM.TimeOut IS NULL)
        GROUP BY
            S.StageNumber,
            S.StageName,
            MONTH(TimeIn), 
            DATENAME(MONTH,TimeIn), 
            YEAR(TimeIn)
    ) A
    RIGHT JOIN (select distinct Month,MonthName,Year from Calendar WHERE DATE >= @StartDate AND DATE < DATEADD (d,1,@EndDate)) C on
        A.MonthNumber = C.Month and
        A.Month = C.MonthName and
        A.Year = C.Year 
    GROUP BY
        A.StageName,
        C.Month,
        C.MonthName,
        C.Year,
        A.Average   
    ORDER BY  
        CASE WHEN @Ordering = 'asc'  THEN C.Year            END ASC, 
        CASE WHEN @Ordering = 'asc'  THEN C.Month           END ASC,
        CASE WHEN @Ordering = 'asc'  THEN A.StageName       END ASC,
        CASE WHEN @Ordering = 'desc' THEN C.Year            END DESC, 
        CASE WHEN @Ordering = 'desc' THEN C.Month           END DESC,
        CASE WHEN @Ordering = 'desc'  THEN A.StageName      END DESC

2 个答案:

答案 0 :(得分:0)

因为order by必须评估每一行,所以我认为它不能最佳地使用索引。将order by替换为row_number()进行默认排序,只撤消订单一次,至少应该阻止单行@Ordering的多次评估。

在下面的伪代码中,原始查询被放入CTE中。 Row_number确定升序排序,在cte下面,如果需要,订单会反转:

;with cte as
(
    SELECT
        A.StageName,
        C.Month,
        ...,
        row_number() over (order by C.Year,C.Month,A.StageName) sortOrder
    FROM
       ...rest of the query, excluding the order by
)
select * --or list the columns without the sortOrder 
from cte
order by sortOrder * case @Ordering when 'desc' then -1 else 1 end 

答案 1 :(得分:0)

虽然我知道你无法摆脱子查询中不同列的apt-get remove android-platform-adb,但你可以让系统更容易。

目前你有

GROUP BY

我猜这是很多数据要经过的。请允许我做一些猜测:

S.StageNumber,
S.StageName,
MONTH(TimeIn), 
DATENAME(MONTH,TimeIn), 
YEAR(TimeIn)

现在,有一些依赖项:

  • 如果您知道MONTH(数字),那么您现在也知道它的名称
  • 我猜测StageName + StageNumber是唯一的并且与StageID直接相关。如果不是,您可能需要在外层再次使用GROUP BY。

这会把我们带到

S.StageNumber,  -- int, 4 bytes
S.StageName, -- string, 20 bytes
MONTH(TimeIn),  -- int, 4 bytes
DATENAME(MONTH,TimeIn),  -- string 5 bytes
YEAR(TimeIn) -- int, 4 byte

这意味着S.StageID, -- int, 4 bytes MONTH(TimeIn), -- int, 4 bytes YEAR(TimeIn) -- int, 4 byte 的排序必须每个记录只运行12个字节而不是之前每个记录的37个字节,并且数字排序比字符串快得多(例如由于上层) /小写,重音等。)

我试图相应地重写查询(未经测试!)。我还将Month-information的获取移动到一个单独的临时表中,这应该对查询优化器有所帮助。

GROUP BY

希望这有帮助。