performance - 从 Sql Server 2008 升级到 Sql Server 2016 后,一个快速的存储过程现在变慢了

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

我们有一个存储过程,它返回落在地​​理空间区域(“地理”)内的所有记录。它使用 CTE(with)、一些联合、一些内部连接并将数据作为 XML 返回;没有争议或前沿,但也不是微不足道的。

此存储过程在 SQL Server 2008 上为我们服务多年。它在相对较慢的服务器上运行不到 1 秒。我们刚刚在具有大量内存和超快 SDD 的超快服务器上迁移到 SQL Server 2016。

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

我们已经更新了这个数据库的索引和统计数据。我们还将数据库的兼容级别从 100 更改为 130。

有趣的是,我重写了存储过程以使用临时表和“插入”而不是使用 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 正在花时间处理许多其他步骤,包括哈希匹配和并行性以及其他标准内容。

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

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

提前致谢。

--

此外,我还建议添加跟踪标志 -T6534 来启动服务的参数。它对查询时间没有影响。我也尝试将选项(QUERYTRACEON 6534)添加到查询的末尾,但同样没有任何区别。

最佳答案

从您提供的查询计划中,我看到空间索引未在较新的服务器版本上使用。 使用空间索引提示来确保查询优化器选择具有空间索引的计划:

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 上的查询计划是串行的。使用选项 (recompile, 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)

关于performance - 从 Sql Server 2008 升级到 Sql Server 2016 后,一个快速的存储过程现在变慢了,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38494618/

相关文章:

mysql - START TRANSACTION 在 BEGIN ... END 上下文或外部和 LOOP 语法中

mysql - mysql中如何使用select语句调用存储过程

Python:(显式)字符串参数会损害性能吗?

vb.net - Visual Studio 2013 每次都进行不必要的构建并且速度很慢

sql-server - 为什么 SQL Server 2008 OLE DB UDL 需要显式指定端口 1433?

sql - T-SQL并发问题: Auction/Bidding System

c# - 如何提高 C# 中 ConcurrentDictionary.Count 的性能

php - 我应该在发送之前在数据库中对电子邮件进行排队,而不是即时发送吗?

mysql - 如何在 SQL 中将 ID 替换为相应的值?

MySQL存储过程1064错误