2011-11-28 69 views
1

我有如下一段sql,雖然它按照預期運行,但它返回結果有點慢(通過慢我說10秒從1000個月的日期範圍返回結果)。它有可能變得更高效和/或更快?只需添加這些有以下幾種指標我有表: -這個SQL代碼可以更有效嗎?

  • 的recordId - 主鍵唯一聚集
  • 部 - 非聚集
  • 方向 - 非聚集
  • LocalCallGroup - 非聚集
  • ServiceProvider - 非成簇
  • 開始時間 - 非成簇
  • 用戶ID - 非成簇
  • UserLocalStartTime - 非聚集
  • UserLocalTimeOffset - 非聚集
  • UserNumber - 非聚集

變量的聲明在這裏,撤職

SET @TerminatingSQL = ' 
    SELECT 
     UserNumber, 
     ImageDirection = ''in'', 
     CallingNumber = CASE WHEN callingnumber IN(''Unavailable'',''Unknown'',''[email protected]'',''[email protected]'') 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'',''[email protected]'',''[email protected]'') 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,@[email protected] OUTPUT 
    END 
ELSE 
    BEGIN 
     SET @TotalCount = @CurrentCount; 
    END 
END 
+7

爲什麼這麼多動態SQL? – gbn

+0

爲了能夠傳入變量並建立多個選擇 –

回答

4

事情,以改善

  • UNION ALL將刪除隱含的DISTINCT。 ImageDirection列確保沒有任何重疊,因此UNION在計劃中添加了額外的步驟

  • 如果您有ROW_NUMBER(),請添加COUNT(*) OVER()以獲取總記錄數。這消除了對第二個呼叫

思想的需要:

  • 你有動態表名,需要這麼醜的串聯?
    除此以外,我認爲沒有必要對動態SQL

  • 考慮使用臨時表來階段性成果,以簡化複雜

+0

是的不幸的是我有基於月份和年份的動態表名稱。因此,例如它的格式爲Table_2011_11 –

+5

@Vince Ashby-Smith:這就是爲什麼RDBMS有分區,所以你不會在這個混亂中結束...... – gbn

+0

是的,我看着分區但是我們沒有正確版本的SQL以允許分區,我們不能購買版本:( –

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