我正在尝试调整下面的存储过程,因为它在我们的网站上每分钟调用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()
我的问题很难衡量改进,因为它们都是如此之快,是否值得我做出这些改变,我是否会看到微小的收益?
答案 0 :(得分: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子句中,只需检查所有其他条件是否具有相同的数据类型,以防止隐式转换。
答案 1 :(得分: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,因此这应该会大大提高性能。
答案 2 :(得分:1)
[IX_HttpCallStatus_tbl] nonclustered [SupplierId]
。 涵盖 [idx_HttpCallStatus_tbl_1]
。[idx_HttpCallStatus_tbl_1] nonclustered [SupplierId], [ScriptTypeId], [SiteTypeId], [SiteName], [HostName], [DayDate], [GoodCalls], [BadCalls], [TotalConnectionTime]
更改为 [SupplierId], [ScriptTypeId], [SiteTypeId], [SiteName], [HostName], [DayDate]
和include列 {{1 }} 就sproc而言,我会在更新上面添加:
[GoodCalls], [BadCalls], [TotalConnectionTime]
并更改where
的前两行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)
答案 3 :(得分: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逻辑