这个sql代码可以提高效率吗?

时间:2011-11-28 10:02:14

标签: sql sql-server sql-server-2008

我有下面的一段sql,虽然它按预期运行,返回结果有点慢(慢速我说的是10秒,从月份日期范围返回1000个结果)。是否有可能提高效率和/或更快?只是添加这些是我在表上的以下索引: -

  • RecordID - 主键唯一群集
  • 部门 - 非群集
  • 方向 - 非群集
  • LocalCallGroup - 非群集
  • ServiceProvider - 非群集
  • StartTime-非群集
  • UserID-非群集
  • UserLocalStartTime - 非群集
  • UserLocalTimeOffset - 非群集
  • UserNumber - 非群集

此处声明变量,已移除

    SET @TerminatingSQL = '
    SELECT 
        UserNumber, 
        ImageDirection = ''in'', 
        CallingNumber = CASE WHEN callingnumber IN(''Unavailable'',''Unknown'',''+44anonymous@10.81.253.12'',''0anonymous@10.81.253.12'') THEN ''Anonymous'' ELSE callingnumber END,
        CalledNumber,
        StartTime = dateadd(ms,(-datepart(ms,(startTime))),(startTime)),
        AnswerTime = dateadd(ms,(-datepart(ms,(answerTime))),(answerTime)),
        ReleaseTime =  dateadd(ms,(-datepart(ms,(releaseTime))),(releaseTime)),         
        CallDuration =  dateadd(ms,(-datepart(ms,(releaseTime))),(releaseTime)) - dateadd(ms,(-datepart(ms,(answerTime))),(answerTime)),
        TotalDuration = dateadd(ms,(-datepart(ms,(releaseTime))),(releaseTime)) - dateadd(ms,(-datepart(ms,(startTime))),(startTime)),
        terminationCause,
        recordID
    FROM
        dbo.TABLEA' + @Table +'
    WHERE
        serviceProvider IN ( SELECT serviceProvider FROM ccNumbers WHERE CRMID = ' + CONVERT(VARCHAR(10),@CrmId,103) + ')
        AND startTime between ''' + CONVERT(VARCHAR(10),@Fromdate,112) + ''' AND ''' + CONVERT(VARCHAR(10), @ToDate, 112) + '''
        AND Direction = ''terminating''
        AND (Department = ''' + @Department + ''' OR ''' + @Department + ''' = ''ALL'')
        AND (userid = ''' + @Userid + ''' OR ''' + @Userid + ''' = ''ALL'')'

    SET @OriginatingSQL = '
    SELECT 
        UserNumber, 
        ImageDirection = ''out'', 
        CallingNumber = CASE WHEN callingnumber IN(''Unavailable'',''Unknown'',''+44anonymous@10.81.253.12'',''0anonymous@10.81.253.12'') THEN ''Anonymous'' ELSE callingnumber END,
        CalledNumber,
        StartTime = dateadd(ms,(-datepart(ms,(startTime))),(startTime)),
        AnswerTime = dateadd(ms,(-datepart(ms,(answerTime))),(answerTime)),
        ReleaseTime =  dateadd(ms,(-datepart(ms,(releaseTime))),(releaseTime)),         
        CallDuration =  dateadd(ms,(-datepart(ms,(releaseTime))),(releaseTime)) - dateadd(ms,(-datepart(ms,(answerTime))),(answerTime)),
        TotalDuration = dateadd(ms,(-datepart(ms,(releaseTime))),(releaseTime)) - dateadd(ms,(-datepart(ms,(startTime))),(startTime)),
        terminationCause,
        recordID
    FROM
        dbo.TABLEA' + @Table +'
    WHERE
        serviceProvider IN ( SELECT serviceProvider FROM ccNumbers WHERE CRMID = ' + CONVERT(VARCHAR(10),@CrmId,103) + ')
        AND startTime between ''' + CONVERT(VARCHAR(10),@Fromdate,112) + ''' AND ''' + CONVERT(VARCHAR(10), @ToDate, 112) + '''
        AND Direction = ''originating''
        AND (Department = ''' + @Department + ''' OR ''' + @Department + ''' = ''ALL'')
        AND (userid = ''' + @Userid + ''' OR ''' + @Userid + ''' = ''ALL'')'

    SET @MainSelectSQL = @TerminatingSQL + ' Union '  + @OriginatingSQL

    SET @MainSQL = 'SELECT TOP (' + @PageSize + ') 
        [t1].CalledNumber,
        [t1].CallingNumber,
        [t1].UserNumber, 
        [t1].StartTime,
        [t1].AnswerTime,
        [t1].ReleaseTime,
        [t1].ImageDirection,
        [t1].CallDuration,
        [t1].TotalDuration,
        [t1].TerminationCause
    FROM (
        SELECT ROW_NUMBER() OVER (
            ORDER BY [t0].startTime) as [row_number], 
            [t0].CalledNumber,
            [t0].CallingNumber,
            [t0].UserNumber,
            [t0].StartTime,
            [t0].AnswerTime,
            [t0].ReleaseTime,
            [t0].ImageDirection,
            [t0].CallDuration,
            [t0].TotalDuration,
            [t0].TerminationCause
        FROM
            (' + @MainSelectSQL + ')  AS [t0] 
          )  AS [t1]

    WHERE [t1].[row_number] > ' + @Page + ' * ' + @PageSize +';'

    EXEC (@MainSQL)

-- Work out the total number of rows, but don't bother if we have the number already (i.e. when they keep the same parameters and just click paging.

IF  (@CurrentCount IS NULL)
    BEGIN
        DECLARE @TotalCountSQL nvarchar(4000)
        DECLARE @ParameterList NVARCHAR(4000)   

        SET @ParameterList = '@TotalCount int OUTPUT'
        SET @TotalCountSQL = 'SELECT @TotalCount = COUNT(recordId) FROM (' + @MainSelectSQL + ') as a'

        EXEC SP_EXECUTESQL @TotalCountSQL,@ParameterList,@TotalCount=@TotalCount OUTPUT
    END
ELSE
    BEGIN
        SET @TotalCount = @CurrentCount;
    END
END

2 个答案:

答案 0 :(得分:4)

需要改进的地方

  • UNION ALL将删除隐含的DISTINCT。 ImageDirection列确保无论如何都没有重叠,因此UNION在计划中添加了额外的步骤

  • 如果您有ROW_NUMBER(),请添加COUNT(*) OVER ()以获取总记录数。这消除了对第二次呼叫

  • 的需要

思想:

  • 您是否拥有需要如此难以连接的动态表名? 除此之外,我认为不需要动态SQL

  • 考虑使用临时表来分析结果以简化复杂性

答案 1 :(得分:0)

如果由于变量表名只需要动态SQL,请考虑仅使用动态SQL将所需数据提取到临时表中,然后使用临时表将所有SQL写为常规SQL(非动态)作为数据来源。

DECLARE @Table_Name VARCHAR(255) = 'Table_2011_11'

CREATE TABLE #temp (
    Number INT,
    Name VARCHAR(64)
)

DECLARE @sql VARCHAR(512) = 'INSERT INTO #temp(Number) SELECT UserNumber FROM ' + @Table_Name
exec sp_sqlexec @sql

select * from #temp