2011-08-15 40 views
7

我有一个特殊的SQL查询,似乎遭受了一个神秘的性能问题。下面是该查询:需要使用聚合函数来提高SQL查询的性能

SELECT COUNT(LengthOfTime) AS TotalTime, 
     SUM(LengthOfTime) AS TotalLength, 
     SUM(LengthOfTime)/COUNT(LengthOfTime) AS AverageTime, 
     SUM(Pops)/COUNT(LengthOfTime) AS AveragePop 
    FROM ((SELECT * 
      FROM (SELECT *, ID & YearRec AS ID2 
        FROM MyFirstTable 
       UNION ALL 
       SELECT *, ID & YearRec AS ID2 
        FROM Table2011) AS TEMP 
      WHERE STARTTIME >= '8/1/2011 00:00:00' 
      AND StartTime <= '8/5/2011 23:59:59') AS TEMP2 
    JOIN AppleTable ON TEMP2.Reason = AppleTable.Skills) 
    JOIN PeopleTable ON TEMP2.Operator = PeopleTable.Operators 
WHERE AppleTable.[ON] = 1 
    AND PeopleTable.[ON] = 1 
    AND Rec_Type = 'SECRET AGENT' 

这里的问题是,这个查询运行速度很快(0:00至0:02),当5天跨度运行,但速度很慢(1:20至1:45 )为期6天。

表中每天约有105,000条记录(MyFirstTable和Table2011)。

我的问题:有没有上限,你看到在SQL Server中的一个严重的性能问题之前,你可以通过聚合函数的行数? (目前使用的是2008 R2)

+0

是您的统计数据,您是否最近重新编制了索引? –

+0

您的声音可能会从内存操作溢出到需要磁盘的操作。我不熟悉MySQL调优细节,但是如果有临时工作区的内存分配参数,可以尝试增加它。 –

+1

@Jim:它不是mySQL ... –

回答

4

不,没有预定义的聚合函数上限。

在性能上的偏斜可能受下列一种或多种:

  • 旧的和/或不适合的索引结构
  • 缓存执行计划
  • 缓存数据
  • 数据大小不是统一(前五天是10行,第六是100 B行)

您可以运行查询在SSMS中查看实际的执行计划。这将告诉你运行查询的成本最高的地方,这将帮助你确定最佳的行动方案。

编辑基于评论:

如果没有在Table2011包含[STARTTIME]索引,然后创建一个。如果有索引,但它被忽略,那么你必须弄清楚为什么。如果分解,那么重建索引肯定会有帮助。下面是如何重建

ALTER INDEX [YourIndexName] ON [dbo].[Table2011] REBUILD WITH (STATISTICS_NORECOMPUTE = ON);

或者你可以在SSMS做到这一点 - 浏览到对象浏览器中的具体指标,右击并重建。

+0

我看着实际的执行计划。 97%的成本来自Table2011的“表扫描”。这是我在UNION之前预测开始时间 – dan042988

+0

@ dan042988回答更新 –

+0

谢谢您指引我正确的方向。我结束了使用的实际执行计划,以创建新的索引 使用'[数据库名] GO 创建非聚集索引[QueryIndex1] ON [DBO]。[Table2011]([Rec_Type],[开始时间]) 包括:([运算符],[LengthOfTime],[Pop],[Reason]) GO' – dan042988

9

简短回答:不,不会有一些魔术数量的记录会导致MSSQL开始表现不佳。

现在,有可能查询不会很好地扩展,结果是数据集越大,[指数级]越差。

您将遇到的一个大问题是您在预测 UNIONED语句后的StartTime 。相反,尝试在UNION之前的两次选择中进行预测。这应该会产生巨大的差异,特别是如果您在StartTime上对两个表格进行索引(在这些表格上生成索引查找)。

SELECT * FROM (
SELECT *, ID & YearRec AS ID2 FROM MyFirstTable 
    WHERE STARTTIME >= '8/1/2011 00:00:00' 
    AND STARTTIME <= '8/5/2011 23:59:59' 
UNION ALL SELECT *, ID & YearRec AS ID2 
FROM Table2011 
    WHERE STARTTIME >= '8/1/2011 00:00:00' 
    AND STARTTIME <= '8/5/2011 23:59:59' 
) AS TEMP 

您也许可以对代码进行一些额外的重构。

+0

+1 - 关于WHERE位置的很好的一点。 –

+0

我会给+1发现'UNION'的位置。如果它可以进一步移出(将两个表分开连接到另一个并分组,然后使用聚集体),则可能会进一步提高性能。您最终可能甚至不需要UNION,只使用'countFromSubquery1 + countFromSubquery2 AS TotalTime'等。 –

+0

对不起,但查询优化器应处理此问题 - 查询计划应显示此条件是否应用于子外部联盟。应该使ZERO在性能上有所不同。 – TomTom