从Sql Server 2008升级到Sql Server 2016后,快速的存储过程现在很慢

时间:2016-07-21 03:56:19

标签: performance sql-server-2008 stored-procedures common-table-expression sql-server-2016

我们有一个存储过程,它返回属于地理空间区域(“地理位置”)的所有记录。它使用CTE(带),一些联合,一些内连接并将数据作为XML返回;没有争议或前沿,但也不是无足轻重的。

这个存储过程在SQL Server 2008上已经很好地服务了很多年。它在相对较慢的服务器上运行1秒钟。我们刚刚在具有大量内存和超快速SDD的超高速服务器上迁移到SQL Server 2016。

整个数据库和相关应用程序在这台新服务器上非常快,我们对它非常满意。然而,这一个存储过程在16秒而不是1秒内运行 - 完全相同的参数和完全相同的数据集。

我们已更新此数据库的索引和统计信息。我们还将数据库的兼容级别从100更改为130.

有趣的是,我重写了存储过程以使用临时表和'insert'而不是使用CTE。这使得时间从16秒减少到4秒。

执行计划没有提供任何关于瓶颈可能存在的明显见解。

我们有点陷入困境。接下来我们该怎么办?提前谢谢。

-

我现在花在这个问题上的时间比我承认的要多。我已将存储过程归结为以下查询以演示此问题。

drop table #T 

declare @viewport sys.geography=convert(sys.geography,0xE610000001041700000000CE08C22D7740C002370B7670F4624000CE08C22D7740C002378B5976F4624000CE08C22D7740C003370B3D7CF4624000CE08C22D7740C003378B2082F4624000CE08C22D7740C003370B0488F4624000CE08C22D7740C004378BE78DF4624000CE08C22D7740C004370BCB93F4624000CE08C22D7740C004378BAE99F4624000CE08C22D7740C005370B929FF4624000CE08C22D7740C005378B75A5F4624000CE08C22D7740C005370B59ABF462406F22B7698E7640C005370B59ABF462406F22B7698E7640C005378B75A5F462406F22B7698E7640C005370B929FF462406F22B7698E7640C004378BAE99F462406F22B7698E7640C004370BCB93F462406F22B7698E7640C004378BE78DF462406F22B7698E7640C003370B0488F462406F22B7698E7640C003378B2082F462406F22B7698E7640C003370B3D7CF462406F22B7698E7640C002378B5976F462406F22B7698E7640C002370B7670F4624000CE08C22D7740C002370B7670F4624001000000020000000001000000FFFFFFFF0000000003)

declare @outputControlParameter nvarchar(max) = 'a value passed in through a parameter to the stored that controls the nature of data to return. This is not the solution you are looking for'

create table #T
    (value int)

insert into #T 
select 136561 union 
select 16482 -- These values are sourced from parameters into the stored proc

select 
      [GeoServices_Location].[GeographicServicesGatewayId],
      [GeoServices_Location].[Coordinate].Lat,
      [GeoServices_Location].[Coordinate].Long

      from GeoServices_Location

      inner join GeoServices_GeographicServicesGateway
            on    GeoServices_Location.GeographicServicesGatewayId = GeoServices_GeographicServicesGateway.GeographicServicesGatewayId

      where 
        (
            (len(@outputControlParameter) > 0 and GeoServices_Location.GeographicServicesGatewayId in (select value from #T)) 
            or (len(@outputControlParameter) = 0 and GeoServices_Location.Coordinate.STIntersects(@viewport) = 1)
        )
        and GeoServices_GeographicServicesGateway.PrimarilyFoundOnLayerId IN (3,8,9,5) 

GO

将存储过程归结为此,它在SQL Server 2008上运行0秒,在SQL Server 2016上运行5秒

http://www.filedropper.com/newserver-slowexecutionplan

http://www.filedropper.com/oldserver-fastexecutionplan

Windows Server 2016在Geospatial Intersects调用中窒息了94%的时间。 Sql Server 2008正在花时间处理其他一些步骤,包括Hash Matching和Parallelism以及其他标准内容。

记住这是同一个数据库。一个刚被复制到SQL Server 2016计算机并且其兼容性级别提高了。

为了解决这个问题,我实际上已经重写了存储过程,以便Sql Server 2016不会阻塞。我跑了250毫秒。但是,这不应该首先发生,我担心还有其他以前经过精心调整的查询或存储过程现在无法有效运行。

提前致谢。

-

此外,我有一个建议是添加traceflag -T6534来启动服务的参数。它对查询时间没有影响。此外,我也尝试在查询结尾添加选项(QUERYTRACEON 6534),但同样没有任何区别。

2 个答案:

答案 0 :(得分:5)

根据您提供的查询计划,我发现较新的服务器版本不使用空间索引。 使用空间索引提示确保查询优化器选择具有空间索引的计划:

select 
    [GeoServices_Location].[GeographicServicesGatewayId],
    [GeoServices_Location].[Coordinate].Lat,
    [GeoServices_Location].[Coordinate].Long
from GeoServices_Location with (index ([spatial_index_name]))...

我看到提示的问题是查询谓词中的OR操作,所以我的提示实际上在这种情况下无效。 但是,我看到谓词依赖于@outputControlParameter,因此重写查询以便将这两个案例分开可能会有所帮助(请参阅下面的建议)。 此外,根据您的查询计划,我发现SQL 2008上的查询计划是并行的,而SQL 2016是串行的。使用选项(重新编译,querytraceon 8649)来强制并行计划(如果你的新超高速服务器有更多核心,那么应该有帮助)。

if (len(@outputControlParameter) > 0)
    select 
    [GeoServices_Location].[GeographicServicesGatewayId],
    [GeoServices_Location].[Coordinate].Lat,
    [GeoServices_Location].[Coordinate].Long

    from GeoServices_Location

    inner join GeoServices_GeographicServicesGateway
    on GeoServices_Location.GeographicServicesGatewayId = GeoServices_GeographicServicesGateway.GeographicServicesGatewayId

    where 
    GeoServices_Location.GeographicServicesGatewayId in (select value from #T))
    and GeoServices_GeographicServicesGateway.PrimarilyFoundOnLayerId IN(3,8,9,5) 
    option (recompile, querytraceon 8649)
else
    select
    [GeoServices_Location].[GeographicServicesGatewayId],
    [GeoServices_Location].[Coordinate].Lat,
    [GeoServices_Location].[Coordinate].Long

    from GeoServices_Location with (index ([SPATIAL_GeoServices_Location]))

    inner join GeoServices_GeographicServicesGateway
    on GeoServices_Location.GeographicServicesGatewayId = GeoServices_GeographicServicesGateway.GeographicServicesGatewayId

    where 
    GeoServices_Location.Coordinate.STIntersects(@viewport) = 1
    and GeoServices_GeographicServicesGateway.PrimarilyFoundOnLayerId IN (3,8,9,5) 
    option (recompile, querytraceon 8649)

答案 1 :(得分:1)

  1. 检查新服务器(DB)与旧服务器(DB)配置上的数据/日志文件的增长情况:查询运行的数据库+ tempdb
  2. 检查日志中的I / O缓冲区错误
  3. 检查数据库的恢复模型 - 简单与完整/批量
  4. 这是一致行为吗?也许在执行过程中正在运行一个进程?
  5. 关于统计/索引 - 您确定它正在运行正确的数据样本吗? (看看计划)
  6. 可以检查/完成更多的事情 - 但这个问题没有足够的信息。