0

我正在尝试在我们的网站上将下面的存储过程调整为每分钟 30k 次。

CREATE PROCEDURE [dbo].[mltHttpCallStatus] 

    @SupplierId     AS INTEGER,
    @CallIsGood     AS BIT,
    @MaxWorkerThreads   AS INT,
    @MaxIOThreads       AS INT,
    @AvailWorkerThreads AS INT,
    @AvailIOThreads     AS INT,
    @ScriptTypeId       AS INT,
    @SiteTypeId         AS VARCHAR(50),
    @ConnectionTime     AS INT,
    @SiteName       AS VARCHAR(50),
    @HostName       AS VARCHAR(50)

AS

    --DEBUG BEN (Flight details keep failing) 07012008 19:30
    --Return
SET NOCOUNT ON

DECLARE @GoodCalls      AS INT,
    @BadCalls       AS INT

SET @BadCalls = 0
SET @GoodCalls = 0

IF @CallIsGood = 1
    SET @GoodCalls = 1

ELSE
    SET @BadCalls = 1

    UPDATE  HttpCallStatus_tbl SET
        GoodCalls       = GoodCalls + @GoodCalls,
        BadCalls        = BadCalls + @BadCalls,
        TotalConnectionTime = TotalConnectionTime + @ConnectionTime
     --WHERE dbo.datepart_fn(DayDate) = dbo.datepart_fn(getDate())
    WHERE DATEADD(dd, 0, DATEDIFF(dd, 0, DayDate)) = DATEADD(dd, 0, DATEDIFF(dd, 0, GETDATE()))
        AND DATEPART(HOUR, DayDate) = DATEPART(HOUR, getDate()) 
        AND SupplierId   = @SupplierId
        AND ScriptTypeId = @ScriptTypeId
        AND SiteTypeId = @SiteTypeId
        AND SiteName = @SiteName
        AND HostName = @HostName

    IF @@ROWCOUNT = 0

    BEGIN
        INSERT INTO HttpCallStatus_tbl (DayDate,SupplierId,GoodCalls,BadCalls,ScriptTypeId,SiteTypeId,TotalConnectionTime, 
                        MaxWorkerThreads,MaxIOThreads,AvailWorkerThreads,AvailIOThreads,SiteName,HostName)
             VALUES (CONVERT(DATETIME, getDate(), 103),
                @SupplierId,
                @GoodCalls,
                @BadCalls,
                @ScriptTypeId,
                @SiteTypeId,
                @ConnectionTime,
                0,
                0,
                0,
                0,
                @SiteName,
                @HostName)
    END

表结构

    Column_name         Type        Length
    DayDate             datetime    8
    SupplierId          int     4
    GoodCalls           int     4
    BadCalls            int     4
    ScriptTypeId                int     4
    SiteTypeId          varchar     50
    TotalConnectionTime         int     4
    MaxWorkerThreads            int     4
    MaxIOThreads                int     4
    AvailWorkerThreads          int     4
    AvailIOThreads              int     4
    SiteName            varchar     50
    HostName            varchar     50
    SearchCount         int     4
    DomainId            int     4

索引

[PK_HttpCallStatus_tbl] clustered, unique, primary key [DayDate],[SupplierId]

[IX_HttpCallStatus_tbl] nonclustered [SupplierId]

[idx_HttpCallStatus_tbl_1]  nonclustered    
[SupplierId], [ScriptTypeId], [SiteTypeId], [SiteName], [HostName]
 , [DayDate], [GoodCalls], [BadCalls], [TotalConnectionTime]

我注意到这些变量是未使用的@MaxWorkerThreads、@MaxIOThreads、@AvailWorkerThreads、@AvailIOThreads。也可以使变量@goodcalls & @Badcalls TINYINTS。我还在插入语句 VALUES (CONVERT(DATETIME, getDate(), 103) 中注意到了这种转换。但我认为这是默认值,因此可以更改为 Getdate()

我的问题是很难衡量改进,因为它们都非常快,我是否值得进行这些更改,我什至会看到一点点收获吗?

4

4 回答 4

2

我认为您在错误的地方进行了优化。您担心插入时一行的转换,而忽略了它前面的 where 子句中的转换/函数。看起来您已将逻辑从标量函数移回 where 子句,这将有所帮助,但我将专注于更改这一点:

WHERE DATEADD(dd, 0, DATEDIFF(dd, 0, DayDate)) = DATEADD(dd, 0, DATEDIFF(dd, 0, GETDATE()))
        AND DATEPART(HOUR, DayDate) = DATEPART(HOUR, getDate()) 

进入可以与索引一起使用的东西。看看 sargability http://en.wikipedia.org/wiki/Sargable并找出一种方法来避免您的数据出现这种情况。那将是真正的收益所在。

此外,仍然在 where 子句中,只需检查所有其他条件是否具有相同的数据类型,以防止隐式转换。

于 2013-01-08T12:59:41.407 回答
2

试试这个:

CREATE PROCEDURE [dbo].[mltHttpCallStatus] 

    @SupplierId     AS INTEGER,
    @CallIsGood     AS BIT,
    @MaxWorkerThreads   AS INT,
    @MaxIOThreads       AS INT,
    @AvailWorkerThreads AS INT,
    @AvailIOThreads     AS INT,
    @ScriptTypeId       AS INT,
    @SiteTypeId         AS VARCHAR(50),
    @ConnectionTime     AS INT,
    @SiteName       AS VARCHAR(50),
    @HostName       AS VARCHAR(50)

AS

    --DEBUG BEN (Flight details keep failing) 07012008 19:30
    --Return
SET NOCOUNT ON

DECLARE @GoodCalls      AS INT,
        @BadCalls       AS INT,
        @StartHour DateTime,
        @EndHour   DateTime

Select  @StartHour = DATEADD(Hour, DATEDIFF(Hour, 0, GETDATE()), 0),
        @EndHour   = DATEADD(Hour, 1 + DATEDIFF(Hour, 0, GETDATE()), 0),
        @BadCalls = 0,
        @GoodCalls = 0

IF @CallIsGood = 1
    SET @GoodCalls = 1

ELSE
    SET @BadCalls = 1

    UPDATE  HttpCallStatus_tbl SET
        GoodCalls       = GoodCalls + @GoodCalls,
        BadCalls        = BadCalls + @BadCalls,
        TotalConnectionTime = TotalConnectionTime + @ConnectionTime
     --WHERE dbo.datepart_fn(DayDate) = dbo.datepart_fn(getDate())
    WHERE DayDate >= @StartHour
        And DayDate < @EndHour
        AND SupplierId   = @SupplierId
        AND ScriptTypeId = @ScriptTypeId
        AND SiteTypeId = @SiteTypeId
        AND SiteName = @SiteName
        AND HostName = @HostName

    IF @@ROWCOUNT = 0

    BEGIN
        INSERT INTO HttpCallStatus_tbl (DayDate,SupplierId,GoodCalls,BadCalls,ScriptTypeId,SiteTypeId,TotalConnectionTime, 
                        MaxWorkerThreads,MaxIOThreads,AvailWorkerThreads,AvailIOThreads,SiteName,HostName)
             VALUES (CONVERT(DATETIME, getDate(), 103),
                @SupplierId,
                @GoodCalls,
                @BadCalls,
                @ScriptTypeId,
                @SiteTypeId,
                @ConnectionTime,
                0,
                0,
                0,
                0,
                @SiteName,
                @HostName)
    END

请注意,我在查询之前计算了开始时间和结束时间,然后将其用作要搜索的日期范围。由于您的主键的第一列是 DayDate,这应该会大大提高性能。

于 2013-01-08T13:39:57.247 回答
1
  1. 删除索引 [IX_HttpCallStatus_tbl] nonclustered [SupplierId]它被 覆盖 [idx_HttpCallStatus_tbl_1]
  2. 将索引更改 [idx_HttpCallStatus_tbl_1] nonclustered [SupplierId], [ScriptTypeId], [SiteTypeId], [SiteName], [HostName], [DayDate], [GoodCalls], [BadCalls], [TotalConnectionTime] 为索引 [SupplierId], [ScriptTypeId], [SiteTypeId], [SiteName], [HostName], [DayDate] 包含 [GoodCalls], [BadCalls], [TotalConnectionTime]

就存储过程而言,我将在更新上方添加:

DECLARE @MinDate DATETIME
DECLARE @MaxDate DATETIME
SET @MinDate=DATEADD(HOUR,DATEPART(HOUR, GETDATE()),CONVERT(DATETIME,CONVERT(VARCHAR,GETDATE(),101)))
SET @MaxDate=DATEADD(HOUR,1,@MinDate)

并更改 where to be 的前两行

WHERE  DayDate>=MinDate AND DayDate<MaxDate 
于 2013-01-08T13:37:28.633 回答
1

几件事:

以下将所有插入的 GETDATE() 转换为 'dd/mm/yyyy' (无时间信息)

CONVERT(DATETIME, getDate(), 103)

因此,可以将数据类型更改为 DATE 而不是 DATETIME。通过该更改,可以更改/删除以下项目:

CONVERT(DATETIME, getDate(), 103) 

Can change to:

CAST(GETDATE() AS DATE)

这可以一起删除,因为时间部分没有被保存:

AND DATEPART(HOUR, DayDate) = DATEPART(HOUR, getDate()) 

DATEADD(dd, 0, DATEDIFF(dd, 0, DayDate)) = DATEADD(dd, 0, DATEDIFF(dd, 0, GETDATE()))

可以改为:

DayDate = CAST(GETDATE() AS DATE)

而且因为您使用的是 SQL Server 2008+,所以您可以使用 MERGE 而不是 UPDATE/INSERT 逻辑

http://technet.microsoft.com/en-us/library/bb510625.aspx

于 2013-01-08T13:45:03.527 回答