由于调用主表,SQL查询运行缓慢

时间:2013-12-12 14:47:20

标签: sql sql-server performance

我正在尝试加速查询,但我无法看到我需要做的查询如何,旧的查询使用的是慢速的函数,所以我已经替换它们,这会加快查询速度但是当完整的查询放在一起它没有更快。问题是我必须为每个子查询调用我的主表,其中有10个以下是查询的一部分,因为完整的东西有点长,应该让你知道问题是什么。

非常感谢!

托马斯

新守则 -

SELECT DISTINCT CAST(FLOOR(CAST(DATEADD(dd, - DATEPART(dd, msValidFrom) + 1, msValidFrom) AS FLOAT)) AS DATETIME) AS MemMonth,
    (SELECT COUNT(DISTINCT me_csID) AS Expr1
    FROM dbo.tblMembershipStatus 
    WHERE (ms_memID IN (@memID)) 
        AND (msDurationType IN (@memType)) 
        AND (CAST(FLOOR(CAST(DATEADD(dd, - DATEPART(dd, MainMonth.msValidFrom) + 1, MainMonth.msValidFrom) AS FLOAT)) AS DATETIME)) 
        BETWEEN CAST(FLOOR(CAST(DATEADD(dd, - DATEPART(dd, msValidFrom) + 1, msValidFrom) AS FLOAT)) AS DATETIME) 
        AND CAST(FLOOR(CAST(DATEADD(dd, - DATEPART(dd, msValidUntil) + 1, msValidUntil) AS FLOAT)) AS DATETIME)) AS active
FROM tblMembershipStatus AS MainMonth
WHERE (CAST(FLOOR(CAST(DATEADD(dd, - DATEPART(dd, msValidFrom) + 1, msValidFrom) AS FLOAT)) AS DATETIME) BETWEEN @StartDate AND @EndDate) 
GROUP BY msValidFrom
ORDER BY MemMonth

相同的代码,但它看起来如何 -

SELECT Purple7Master.dbo.fnc_GetMonthStart(msValidFrom) AS [MemMonth],
    (SELECT COUNT(DISTINCT me_csID) AS Expr1
    FROM dbo.tblMembershipStatus
    WHERE (ms_memID IN (@memID)) 
        AND (msDurationType IN (@memType)) 
        AND (Purple7Master.dbo.fnc_GetMonthStart(MainMonth.msValidFrom) 
        BETWEEN Purple7Master.dbo.fnc_GetMonthStart(msValidFrom) 
        AND Purple7Master.dbo.fnc_GetMonthStart(msValidUntil))) AS [active]     
FROM tblMembershipStatus AS MainMonth
WHERE (Purple7Master.dbo.fnc_GetMonthStart(msValidFrom) BETWEEN @StartDate AND @EndDate)
GROUP BY Purple7Master.dbo.fnc_GetMonthStart(msValidFrom)
ORDER BY MemMonth

2 个答案:

答案 0 :(得分:0)

这里有很多工作要做,这只是你开始的部分答案。

WHERE (CAST(FLOOR(CAST(DATEADD(dd, - DATEPART(dd, msValidFrom) + 1, msValidFrom) AS FLOAT)) AS DATETIME) BETWEEN @StartDate AND @EndDate)

首先这是非常低效的。您正在处理表中的每一行并强制进行全表扫描。

您必须将其更改为

WHERE msValidFrom between @calculated_StartDate and @calculated_endDate

并在msValidFrom上创建一个索引,加速了事情。

你也可以在选择之前做一些计算:

declare @Calculated_date datetime
SET @calcualted_date = cast(floor( ......... @no_calculated_date.....))

答案 1 :(得分:0)

让我试着改写一下你所拥有的内容,以及那些完全浪费的转换会导致你的查询被删除。您希望在给定时间段@StartDate,@ EndDate之间为特定成员ID @memID和成员资格持续时间@memType

的每个月基数计数

显示表格结构和示例数据会有所帮助,但让我们看一下您的转化正在做什么以及为什么它可能过度杀伤。

CAST( FLOOR( CAST( DATEADD(dd, - DATEPART(dd, msValidFrom) + 1, msValidFrom) AS FLOAT)) AS DATETIME) AS MemMonth,

看着内心的......

DatePart(dd, msValidFrom) returns the DAY a member is valid from ex: 12th of the month
DateAdd( dd, -DatePart(dd, msValidFrom) +1, msValidFrom ) is basically saying 
Take Dec 12, subtract 12 days to get to last day of November 30, then add 1 to bring it 
back to the first day of December, so you have the month 12 (December)

为什么不使用

DatePart( mm, msValidFrom ) to give you 12 (December).  

SQL处理任何日期/时间组件。

这本身就可以简化你的头痛。

为了帮助,我会在你的tblMembershipStatus ON上有一个索引

( ms_memID, msDurationType, msValidFrom )

现在,您的OUTER WHERE子句。你在那里做同样的事情,如果日期上有索引。我会以适当的月份开始/月末格式提供你的@StartDate和@EndDate

开始日期类似于

@StartDate = '2013-11-01'  (which defaults to 12:00:00 AM)
@EndDate = '2013-12-01'  (which also defaults to 12:00:00 AM)

然后,你的WHERE子句可能是

WHERE 
      ms_memID in @memID
  AND msDurationType in @memType
  AND msValidFrom >= @StartDate 
  AND msValidFrom < @EndDate  (notice not <= end date which would include Dec 1)

最后你的小组。您可以通过msValidFrom获得它,但是没有聚合(sum,min,max,avg),因为您正在进行DISTINCT,如果在给定月份,您有人在一个月的所有不同日期注册成为会员,你将获得每一天的计数,但这是一个非常艰难的方式。我建议按照

的方式做点什么
SELECT 
      datepart( yyyy, MS.msValidFrom ) memberYear,
      datepart( mm, MS.msValidFrom ) memberMonth,
      COUNT(*) as ActiveMembers
   from
      dbo.tblMembershipStatus MS
   WHERE 
          MS.ms_memID = @memID
      AND MS.msDurationType = @memType
      AND MS.msValidFrom >= @StartDate
      AND MS.msValidUntil < @EndDate
   group by
      datepart( yyyy, MS.msValidFrom ),
      datepart( mm, MS.msValidFrom )

但同样,这是没有看到实际的表结构,示例数据,也没有预期的期望结果(建议您更新原始帖子。不要使用制表符对齐,但空格,然后按Ctrl + K来阻止格式化)