Sql server 优化TSQL存储过程

Sql server 优化TSQL存储过程,sql-server,tsql,stored-procedures,query-optimization,Sql Server,Tsql,Stored Procedures,Query Optimization,我正在尝试调整下面的存储过程,因为它在我们的网站上每分钟被调用30k次 CREATE PROCEDURE [dbo].[mltHttpCallStatus] @SupplierId AS INTEGER, @CallIsGood AS BIT, @MaxWorkerThreads AS INT, @MaxIOThreads AS INT, @AvailWorkerThreads AS INT, @AvailIOT

我正在尝试调整下面的存储过程,因为它在我们的网站上每分钟被调用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、, @可用线程。也可以使变量@goodcalls和@Badcalls变为TINYINTS。 我还注意到insert语句值(CONVERT(DATETIME,getDate(),103)中存在这种转换,但我认为这是默认值,因此可以更改为getDate()


我的问题是很难衡量这些改进,因为它们都很快,值得我做这些更改吗?我甚至会看到一点好处吗?

我认为您在错误的地方进行了优化。您担心的是insert上一行的转换,而忽略了它前面where子句中的转换/函数。看起来假设您已将逻辑从标量函数移回where子句,这将有所帮助,但我将重点更改以下内容:

WHERE DATEADD(dd, 0, DATEDIFF(dd, 0, DayDate)) = DATEADD(dd, 0, DATEDIFF(dd, 0, GETDATE()))
        AND DATEPART(HOUR, DayDate) = DATEPART(HOUR, getDate()) 
看看可搜索性,找出一种方法来避免你的数据出现这种情况。这才是真正的收益所在


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

我认为您在错误的位置进行了优化。您担心的是insert上一行的转换,而忽略了它前面where子句中的转换/函数。看起来您移动了t他将逻辑从标量函数返回where子句,这将有所帮助,但我将重点更改以下内容:

WHERE DATEADD(dd, 0, DATEDIFF(dd, 0, DayDate)) = DATEADD(dd, 0, DATEDIFF(dd, 0, GETDATE()))
        AND DATEPART(HOUR, DayDate) = DATEPART(HOUR, getDate()) 
看看可搜索性,找出一种方法来避免你的数据出现这种情况。这才是真正的收益所在

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

  • 删除索引
    [IX\u HttpCallStatus\u tbl]非聚集的[SupplierId]
    它包含在
    [idx\u HttpCallStatus\u tbl\u 1]
  • 将索引更改为非聚集的[SupplierId]、[ScriptTypeId]、[SiteTypeId]、[SiteName]、[HostName]、[DayDate]、[GoodCalls]、[BadCalls]、[TotalConnectionTime]上的索引和列
    [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  DayDate>=MinDate AND DayDate<MaxDate 
    
    其中DayDate>=MinDate和DayDate
    
  • 删除索引
    [IX\u HttpCallStatus\u tbl]非聚集的[SupplierId]
    它包含在
    [idx\u HttpCallStatus\u tbl\u 1]
  • 将索引更改为非聚集的[SupplierId]、[ScriptTypeId]、[SiteTypeId]、[SiteName]、[HostName]、[DayDate]、[GoodCalls]、[BadCalls]、[TotalConnectionTime]
  • 上的索引和列
    [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  DayDate>=MinDate AND DayDate<MaxDate 
    
    WHERE DayDate>=MinDate和DayDate尝试以下方法:

    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
    
    创建过程[dbo]。[mltHttpCallStatus]
    @供应商ID为整数,
    @卡利斯古德一丝不苟,
    @MaxWorkerThreads为INT,
    @MaxIOThreads作为INT,
    @AvailWorkerThreads为INT,
    @可用线程为INT,
    @ScriptTypeId为INT,
    @SiteTypeId为VARCHAR(50),
    @ConnectionTime为INT,
    @站点名称为VARCHAR(50),
    @主机名为VARCHAR(50)
    作为
    --调试本(航班详细信息持续失败)07012008 19:30
    --返回
    不计较
    将@GoodCalls声明为INT,
    @BadCalls作为INT,
    @我们的日期时间,
    @结束时间日期时间
    选择@StartHour=DATEADD(Hour,DATEDIFF(Hour,0,GETDATE()),0),
    @EndHour=DATEADD(Hour,1+DATEDIFF(Hour,0,GETDATE()),0),
    @BadCalls=0,
    @GoodCalls=0
    如果@CallIsGood=1
    设置@GoodCalls=1
    其他的
    设置@BadCalls=1
    更新HttpCallStatus\u tbl集合
    GoodCalls=GoodCalls+@GoodCalls,
    BadCalls=BadCalls+@BadCalls,
    TotalConnectionTime=TotalConnectionTime+@ConnectionTime
    --其中dbo.datepart_fn(DayDate)=dbo.datepart_fn(getDate())
    其中DayDate>=@StartHour
    和DayDate<@EndHour
    和SupplierId=@SupplierId
    和ScriptTypeId=@ScriptTypeId
    和SiteTypeId=@SiteTypeId
    和SiteName=@SiteName
    和HostName=@HostName
    如果@@ROWCOUNT=0
    开始
    插入到HttpCallStatus_tbl(DayDate、SupplierId、GoodCalls、BadCalls、ScriptTypeId、SiteTypeId、TotalConnectionTime、,
    MaxWorkerThreads、MaxIOThreads、AvailWorkerThreads、AvailIOThreads、SiteName、主机名)
    值(转换(DATETIME,getDate(),103),
    @供应商,
    @再见,
    @坏消息,
    @脚本类型ID,
    @SiteTypeId,
    @连接时间,
    0,
    0,
    0,
    0,
    @站点名称,
    @主机名)
    结束
    
    请注意,我在查询之前计算了开始时间和结束时间,然后将其用作要搜索的日期范围。由于主键的第一列是DayDate,这将大大提高性能。

    尝试以下方法:

    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
    
    创建过程[dbo]。[mltHttpCallStatus]
    @供应商ID为整数,
    @卡利斯古德一丝不苟,
    @MaxWorkerThreads为INT,
    @MaxIOThreads作为INT,
    @AvailWorkerThreads为INT,
    @有效面积
    
    DayDate = CAST(GETDATE() AS DATE)