更新表的存储过程非常慢。为什么?

时间:2015-10-27 16:17:56

标签: sql sql-server tsql

我有一个简单的存储过程,它接受一堆参数来更新表中的现有记录。使用其他存储过程创建和删除记录只需要很少的时间来执行。但是,执行更新存储过程最多需要60秒,我无法理解为什么。

我已经尝试过这篇SO文章的提案,但没有任何运气:SQL Server: Query fast, but slow from procedure

这是最初的SP:

CREATE PROCEDURE [dbo].sp_Update
        @OwnerId uniqueidentifier,
        @DealId uniqueidentifier,
        @Title nvarchar(250),
        @Description nvarchar(MAX),
        @ProjectValue money,
        @Country nvarchar(250),
        @CountryRegion nvarchar(MAX),
        @WorldRegion nvarchar(250),
        @MarketSector nvarchar(250),
        @ProjectStage nvarchar(250),
        @CreationDate datetime,
        @ExpiryDate datetime,
        @ImageFilePath nvarchar(max),
        @IsActive bit,
        @IsDeleted bit

AS
BEGIN

    update SomeTable set 
    OwnerId = @OwnerId, 
    Title = @Title,
    Description = @Description, 
    ProjectValue = @ProjectValue, 
    Country = @Country, 
    CountryRegion = @CountryRegion, 
    WorldRegion = @WorldRegion, 
    MarketSector = @MarketSector, 
    ProjectStage = @ProjectStage,
    CreationDate = @CreationDate, 
    ExpiryDate = @ExpiryDate, 
    ImageFilePath = @ImageFilePath, 
    IsActive = @IsActive,
    IsDeleted = @IsDeleted

    where DealId = @DealId
END

在逐一尝试上述文章中的所有建议之后,我最终得到了这个:

CREATE PROCEDURE [dbo].sp_Update2
        @OwnerId uniqueidentifier,
        @DealId uniqueidentifier,
        @Title nvarchar(250),
        @Description nvarchar(MAX),
        @ProjectValue money,
        @Country nvarchar(250),
        @CountryRegion nvarchar(MAX),
        @WorldRegion nvarchar(250),
        @MarketSector nvarchar(250),
        @ProjectStage nvarchar(250),
        @CreationDate datetime,
        @ExpiryDate datetime,
        @ImageFilePath nvarchar(max),
        @IsActive bit,
        @IsDeleted bit

WITH RECOMPILE
AS
BEGIN
        set quoted_identifier off
        SET ansi_nulls on

        Declare @tempOwnerId uniqueidentifier
        Declare @tempDealId uniqueidentifier
        Declare @tempTitle nvarchar(250)
        Declare @tempDescription nvarchar(MAX)
        Declare @tempProjectValue money
        Declare @tempCountry nvarchar(250)
        Declare @tempCountryRegion nvarchar(MAX)
        Declare @tempWorldRegion nvarchar(250)
        Declare @tempMarketSector nvarchar(250)
        Declare @tempProjectStage nvarchar(250)
        Declare @tempCreationDate datetime
        Declare @tempExpiryDate datetime
        Declare @tempImageFilePath nvarchar(max)
        Declare @tempIsActive bit
        Declare @tempIsDeleted bit

        set @tempOwnerId = @OwnerId
        set @tempDealId = @DealId
        set @tempTitle = @Title
        set @tempDescription = @Description
        set @tempProjectValue = @ProjectValue
        set @tempCountry = @Country
        set @tempCountryRegion = @CountryRegion
        set @tempWorldRegion = @WorldRegion
        set @tempMarketSector = @MarketSector
        set @tempProjectStage = @ProjectStage
        set @tempCreationDate = @CreationDate
        set @tempExpiryDate = @ExpiryDate
        set @tempImageFilePath = @ImageFilePath
        set @tempIsActive = @IsActive
        set @tempIsDeleted = @IsDeleted


    update SomeTable set 
    OwnerId = @tempOwnerId, 
    Title = @tempTitle,
    Description = @tempDescription, 
    ProjectValue = @tempProjectValue, 
    Country = @tempCountry, 
    CountryRegion = @tempCountryRegion, 
    WorldRegion = @tempWorldRegion, 
    MarketSector = @tempMarketSector, 
    ProjectStage = @tempProjectStage,
    CreationDate = @tempCreationDate, 
    ExpiryDate = @tempExpiryDate, 
    ImageFilePath = @tempImageFilePath, 
    IsActive = @tempIsActive,
    IsDeleted = @tempIsDeleted

    where DealId = @tempDealId

    set quoted_identifier off
    SET ansi_nulls on

END

请注意,proc中的ANSI_NULLS和QUOTED_IDENTIFIER以及CREATE而不是ALTER的有趣定位,因为Visual Studio 2015无法像在SSMS中那样处理命令。

我不知道如何加快速度,并且不想沿着将其转换为手动连接字符串的路线,因为一些参数可以接受会使查询不安全的字符(即单引号等)

我也在C#.NET中调用通过Dapper执行存储过程,如果这有任何区别的话。

有什么想法吗?

更新: 这是带有当前索引的表定义:

CREATE TABLE [dbo].[SomeTable] (
    [DealId]        UNIQUEIDENTIFIER NOT NULL,
    [OwnerId]       UNIQUEIDENTIFIER NOT NULL,
    [Title]         NVARCHAR (250)   NOT NULL,
    [Description]   NVARCHAR (MAX)   NOT NULL,
    [ProjectValue]  MONEY            NOT NULL,
    [ProjectStage]  NVARCHAR (250)   NOT NULL,
    [Country]       NVARCHAR (250)   NOT NULL,
    [CountryRegion] NVARCHAR (MAX)   NULL,
    [WorldRegion]   NVARCHAR (250)   NOT NULL,
    [MarketSector]  NVARCHAR (250)   NOT NULL,
    [ImageFilePath] NVARCHAR (MAX)   NULL,
    [CreationDate]  DATETIME         NOT NULL,
    [ExpiryDate]    DATETIME         NOT NULL,
    [IsDeleted]     BIT              DEFAULT ((0)) NOT NULL,
    [IsActive]      BIT              DEFAULT ((0)) NOT NULL,
    PRIMARY KEY CLUSTERED ([DealId] ASC)
);


GO
CREATE NONCLUSTERED INDEX [deal_owners]
    ON [dbo].[SomeTable]([OwnerId] ASC);


GO
CREATE NONCLUSTERED INDEX [deal_ids]
    ON [dbo].[SomeTable]([DealId] ASC);

1 个答案:

答案 0 :(得分:0)

假设DealId是唯一的 - 你每次只更新一行,我不认为这是参数嗅探问题,当某些事情在某个地方以及在其他地方缓慢运行时,这是通常的怀疑。

  • 字段DealId是否已编入索引,是索引中的第一个(或唯一)列?

  • 您是否检查过没有阻塞导致程序运行缓慢?

  • 您是否看过执行的实际计划,如果发生了奇怪的事情,而不是索引搜索+键查找。

Ansi_nulls或quoted_identifier不会影响这样的计划。人们认为这会影响计划,但通常只是计划重复使用,当会话选项不匹配时会创建不同的计划。