由于 select 中的一列,查询时间加倍

Daw*_*wan 3 performance sql-server sql-server-2012 query-performance

我有一个存储过程,它正在计算一些数据并将其插入到临时表中。

然后我从临时表中选择数据。

Select
    AssetId = iAssetId,
    .....
    SpeedKM = fSpeed,
    [Address] = sState +', '+ sDistrict +', ' +sPoi +', ' + sRoad +', '+sPoi,
    MapUrl = @sUrlHeader+'/Report/ReportOnMap/?id='
        +CONVERT(VARCHAR(10), @iCompanyId)+'&ReportName=OverspeedReport'
        +'&AssetId='+ CONVERT(VARCHAR(10), iAssetId)
        +'&MaxSpeed='+ CONVERT(VARCHAR(10), fSpeed)                     
        +'&OverspeedingDate=' + FORMAT(dtutcDateTime, 'dd-MMM-yyyy HH:mm:ss')
        +'&VehicleMonitoringLogId='+ CONVERT(VARCHAR, ol.iVehicleMonitoringId),
    [Locate] = 'Locate'

FROM #overspeedLogs ol
    ORDER BY ol.iAssetId, ol.dtUtcDateTime
Run Code Online (Sandbox Code Playgroud)

现在这个查询大约需要 1:45 分钟来执行。

但是当我删除列时

MapUrl = @sUrlHeader+'/Report/ReportOnMap/?id='
            +CONVERT(VARCHAR(10), @iCompanyId)+'&ReportName=OverspeedReport'
            +'&AssetId='+ CONVERT(VARCHAR(10), iAssetId)
            +'&MaxSpeed='+ CONVERT(VARCHAR(10), fSpeed)                     
            +'&OverspeedingDate=' + FORMAT(dtutcDateTime, 'dd-MMM-yyyy HH:mm:ss')
            +'&VehicleMonitoringLogId='+ CONVERT(VARCHAR, ol.iVehicleMonitoringId),
Run Code Online (Sandbox Code Playgroud)

存储过程只需要35 seconds

有 4 个转换和 1 个日期格式函数,这可能会导致此问题 - 但不更改前端的逻辑(这是一个 RDLC 报告)有没有办法提高它的性能?

将格式更改为转换仍然有类似的结果 - 仍然需要两倍或更多的时间。变量@sUrlHeader 是 VARCHAR(500)。

执行计划

没有 MapUrl 列 - 121919 Rows in 2 minutes https://gist.github.com/mdawood1991/580fadf9031824aa22df

在此处输入图片说明

使用 MapUrl 列 - 121919 Rows in 7 Minutes(对于更多行,增加一倍以上)https://gist.github.com/mdawood1991/33817f95aad40d42631b 在此处输入图片说明

Pau*_*ite 6

时差可能是由于:

  1. 需要返回给客户端的数据量较大;和
  2. FORMAT功能是相对缓慢

您可以FORMAT通过使用 T-SQL 表达式来避免使用,例如:

REPLACE(CONVERT(char(11), dtutcDateTime, 106), SPACE(1), '-') + 
SPACE(1) + 
CONVERT(char(8), @dt, 108);

-- Returns 25-Mar-2016 23:45:19
Run Code Online (Sandbox Code Playgroud)

看:

出于性能原因,您通常还应该避免使用标量T-SQL 函数。这两个计划都使用名为xPT_ConvertTimeToDDHHMMSS. 标量 T-SQL 函数按行执行,其开销类似于运行完整查询(每次)的开销。有 121,861 次函数调用,开销将增加。请改用内嵌函数或 T-SQL 内在函数。

如果不需要,还要检查变量@sUrlHeader是否不是LOB 类型(例如varchar(max))。使用 varchar(8000) 或以下可能会快得多。

您可以通过在 SSMS 中使用Discard Results选项集运行查询来检查查询的原始性能(降低客户端接受结果速度慢的影响):

查询选项

...或通过将查询选择到临时表中:

SELECT
  OverspeedReportId = ol.iVehicleMonitoringId,
  AssetId = iAssetId,
  Registration = sReference,
  CategoryId = iCategoryId,
  CategoryName = sCategoryName,
  SiteId = iSiteId,
  SiteName = sSiteName,
  OverspeedDate = FORMAT(dtutcDateTime, 'dd-MMM-yyyy HH:mm:ss'),
  DistanceTraveledSinceLastOverSpeed = DistanceCoveredKM,
  TimeDifferenceDDDHHMMSS = SUBSTRING(dbo.xPT_ConvertTimeToDDHHMMSS(DiffSeconds,'s'),1,12),
  SpeedKM = fSpeed,
  [Address] = sState +', '+ sDistrict +', ' +sPoi +', ' + sRoad +', '+sPoi,
  MapUrl = @sUrlHeader+'/Report/ReportOnMap/?id='
      +CONVERT(VARCHAR(10), @iCompanyId)+'&ReportName=OverspeedReport'
      +'&AssetId='+ CONVERT(VARCHAR(10), iAssetId)
      +'&MaxSpeed='+ CONVERT(VARCHAR(10), fSpeed)      
      +'&OverspeedingDate=' + FORMAT(dtutcDateTime, 'dd-MMM-yyyy HH:mm:ss')
      +'&VehicleMonitoringLogId='+ CONVERT(VARCHAR, ol.iVehicleMonitoringId),
  [Locate] = 'Locate'
INTO #Results -- NEW!
FROM #overspeedLogs ol
LEFT JOIN VehicleGISAddressLog gis
    ON gis.iVehicleMonitoringId = ol.iVehicleMonitoringId
ORDER BY
    ol.iAssetId, 
    ol.dtUtcDateTime;
Run Code Online (Sandbox Code Playgroud)

要获得最全面的性能数据集合,请直接从SQL Sentry Plan Explorer运行查询。单击“发布到 SQLPerformance.com”工具栏按钮以上传完整会话以在该站点上进行专家分析。

如果您无法做到这一点,STATISTICS IO请至少考虑将输出添加到您的问题中。