Stored Proc /Table 索引改进
Stored Proc /Table Index Improvement
我正在寻找有关我们在应用程序中使用的存储过程的评论。它被调用了很多,我认为还有改进的余地。我还想看看给 Team 和 Opp 添加索引是否对 SP 有帮助。
我们在 Azure 数据库上运行。
table 的架构如下:
CREATE TABLE [dbo].[TeamHistoryMatchUps] (
[Id] UNIQUEIDENTIFIER DEFAULT (newid()) NOT NULL,
[Team] NVARCHAR (100) NOT NULL,
[Opp] NVARCHAR (100) NOT NULL,
[Result] INT NOT NULL,
[MatchResultTime] DATETIME2 (7) DEFAULT (getdate()) NOT NULL,
PRIMARY KEY CLUSTERED ([Id] ASC)
);
这是 SP:
CREATE PROCEDURE [dbo].[up_GetTeamPercentagev2]
@Team NVARCHAR(100),
@Opp NVARCHAR(100)
AS
begin
set nocount ON
declare
@TotalResult INT,
@TeamResult INT
--Total Matchups
Set @TotalResult = (SELECT count(*) FROM TeamHistoryMatchUps
WHERE (Team = @Team OR Opp = @Team) AND (Team = @Opp OR Opp = @Opp)
AND Result = 1)
Set @TeamResult = (SELECT COUNT(*) FROM TeamHistoryMatchUps
WHERE Team = @Team and Opp = @Opp
AND Result = 1)
SELECT (@TeamResult * 100 / @TotalResult) AS Percentage
exit_proc:
end
我应该提到我担心插入,因为就在这个 sp 被调用之前插入到 table 中,然后随着时间的推移进行调用以获得这场比赛的获胜百分比。
在使用显示执行计划几次后,我确实添加了两个非聚集索引。
GO
CREATE NONCLUSTERED INDEX [[IX_MatchUps]
ON [dbo].[TeamHistoryMatchUps]([Result] ASC)
INCLUDE([Team], [Opp]);
GO
CREATE NONCLUSTERED INDEX [IX_MatchupsTeamOpp]
ON [dbo].[TeamHistoryMatchUps]([Team] ASC, [Opp] ASC)
INCLUDE([Result], [MatchResultTime], [MatchUpId]);
这 table 将进入百万行。目前在120k左右。
我在每个团队的 TeamHistoryMatchUps 中添加了 2 条记录,结果为 0 或 1。我试图让它非常简单,以便上面的查询可以。
CREATE PROCEDURE [dbo].[up_GetTeamPercentage]
@Team NVARCHAR(100),
@Opp NVARCHAR(100)
AS
SELECT
SUM(SIGN(result)) * 100 / COUNT(*)
AS Percentage
FROM TeamHistoryMatchUps
WHERE Team = @Team AND Opp = @Opp
但认为更少的写入和更复杂的读取(在 SP 中)将是更好的方法。
如果您不担心插入速度变慢,我会说继续添加索引以获得更好的选择性能。
索引还应过滤结果为 1 的结果。
CREATE NONCLUSTERED INDEX [IX_TeamHistoryMatchUps_team_opp]
ON [dbo].[TeamHistoryMatchUps] ([Team],[Opp])
WHERE result=1
我认为这应该会减少访问(与此同时,我正在尝试看看是否可以只使用一个 SELECT)。建议的索引应该有所帮助。
--Total Matchups
SELECT @TeamResult = COUNT(*) FROM TeamHistoryMatchUps
WHERE Result = 1
AND Team = @Team and Opp = @Opp
SELECT @TotalResult = count(*)
FROM TeamHistoryMatchUps
WHERE Opp = @Team AND Team = @Opp
AND Result = 1
SET @TotalResult= @TotalResult+@TeamResult
答案是,它取决于 TeamHistoryMatchUps table 中的记录数,以及每一列中有多少不同的值。如果 table 中没有大量记录,查询优化器可能仍会创建一个涉及索引扫描的执行计划(读取索引中的每个叶记录以查找匹配项)。这并不比完整 table 扫描快多少。
如果有很多记录并且您在团队中搜索的值和 opp 索引将 return 大约 15% 或更少的行,查询优化器可能会选择使用通过索引查找索引。在这种情况下,会有一个性能提升。
将存储过程参数重新声明为本地参数。它处理参数嗅探,当 WITH RECOMPILE 不起作用时,这也会提高性能(来源:TBD)
创建过程 [dbo].[up_GetTeamPercentagev2]
@Team NVARCHAR(100),
@Opp NVARCHAR(100)
作为
开始
设置 nocount ON
声明</p>
<p>@localTeam NVARCHAR(100),
@localOpp NVARCHAR(100),
@TotalResult INT,
@TeamResult INT</p>
<p>设置@Team = @localTeam
SET @Opp = @localOpp</p>
<p>--总对局
设置 @TotalResult = (SELECT count(*) FROM TeamHistoryMatchUps
WHERE (Team = @localTeam OR Opp = @localTeam) AND (Team = @localOpp OR Opp = @localOpp)
AND 结果 = 1)</p>
<p>设置@TeamResult = (SELECT COUNT(*) 来自 TeamHistoryMatchUps
WHERE Team = @localTeam 和 Opp = @localOpp
AND 结果 = 1)</p>
<p>SELECT (@TeamResult * 100 / @TotalResult) AS 百分比</p>
<p>exit_proc:
结束
***从未在 Azure DB 上尝试过这个
我正在寻找有关我们在应用程序中使用的存储过程的评论。它被调用了很多,我认为还有改进的余地。我还想看看给 Team 和 Opp 添加索引是否对 SP 有帮助。
我们在 Azure 数据库上运行。
table 的架构如下:
CREATE TABLE [dbo].[TeamHistoryMatchUps] (
[Id] UNIQUEIDENTIFIER DEFAULT (newid()) NOT NULL,
[Team] NVARCHAR (100) NOT NULL,
[Opp] NVARCHAR (100) NOT NULL,
[Result] INT NOT NULL,
[MatchResultTime] DATETIME2 (7) DEFAULT (getdate()) NOT NULL,
PRIMARY KEY CLUSTERED ([Id] ASC)
);
这是 SP:
CREATE PROCEDURE [dbo].[up_GetTeamPercentagev2]
@Team NVARCHAR(100),
@Opp NVARCHAR(100)
AS
begin
set nocount ON
declare
@TotalResult INT,
@TeamResult INT
--Total Matchups
Set @TotalResult = (SELECT count(*) FROM TeamHistoryMatchUps
WHERE (Team = @Team OR Opp = @Team) AND (Team = @Opp OR Opp = @Opp)
AND Result = 1)
Set @TeamResult = (SELECT COUNT(*) FROM TeamHistoryMatchUps
WHERE Team = @Team and Opp = @Opp
AND Result = 1)
SELECT (@TeamResult * 100 / @TotalResult) AS Percentage
exit_proc:
end
我应该提到我担心插入,因为就在这个 sp 被调用之前插入到 table 中,然后随着时间的推移进行调用以获得这场比赛的获胜百分比。
在使用显示执行计划几次后,我确实添加了两个非聚集索引。
GO
CREATE NONCLUSTERED INDEX [[IX_MatchUps]
ON [dbo].[TeamHistoryMatchUps]([Result] ASC)
INCLUDE([Team], [Opp]);
GO
CREATE NONCLUSTERED INDEX [IX_MatchupsTeamOpp]
ON [dbo].[TeamHistoryMatchUps]([Team] ASC, [Opp] ASC)
INCLUDE([Result], [MatchResultTime], [MatchUpId]);
这 table 将进入百万行。目前在120k左右。
我在每个团队的 TeamHistoryMatchUps 中添加了 2 条记录,结果为 0 或 1。我试图让它非常简单,以便上面的查询可以。
CREATE PROCEDURE [dbo].[up_GetTeamPercentage]
@Team NVARCHAR(100),
@Opp NVARCHAR(100)
AS
SELECT
SUM(SIGN(result)) * 100 / COUNT(*)
AS Percentage
FROM TeamHistoryMatchUps
WHERE Team = @Team AND Opp = @Opp
但认为更少的写入和更复杂的读取(在 SP 中)将是更好的方法。
如果您不担心插入速度变慢,我会说继续添加索引以获得更好的选择性能。
索引还应过滤结果为 1 的结果。
CREATE NONCLUSTERED INDEX [IX_TeamHistoryMatchUps_team_opp]
ON [dbo].[TeamHistoryMatchUps] ([Team],[Opp])
WHERE result=1
我认为这应该会减少访问(与此同时,我正在尝试看看是否可以只使用一个 SELECT)。建议的索引应该有所帮助。
--Total Matchups
SELECT @TeamResult = COUNT(*) FROM TeamHistoryMatchUps
WHERE Result = 1
AND Team = @Team and Opp = @Opp
SELECT @TotalResult = count(*)
FROM TeamHistoryMatchUps
WHERE Opp = @Team AND Team = @Opp
AND Result = 1
SET @TotalResult= @TotalResult+@TeamResult
答案是,它取决于 TeamHistoryMatchUps table 中的记录数,以及每一列中有多少不同的值。如果 table 中没有大量记录,查询优化器可能仍会创建一个涉及索引扫描的执行计划(读取索引中的每个叶记录以查找匹配项)。这并不比完整 table 扫描快多少。
如果有很多记录并且您在团队中搜索的值和 opp 索引将 return 大约 15% 或更少的行,查询优化器可能会选择使用通过索引查找索引。在这种情况下,会有一个性能提升。
将存储过程参数重新声明为本地参数。它处理参数嗅探,当 WITH RECOMPILE 不起作用时,这也会提高性能(来源:TBD)
创建过程 [dbo].[up_GetTeamPercentagev2]
@Team NVARCHAR(100),
@Opp NVARCHAR(100)
作为
开始
设置 nocount ON
声明</p>
<p>@localTeam NVARCHAR(100),
@localOpp NVARCHAR(100),
@TotalResult INT,
@TeamResult INT</p>
<p>设置@Team = @localTeam
SET @Opp = @localOpp</p>
<p>--总对局
设置 @TotalResult = (SELECT count(*) FROM TeamHistoryMatchUps
WHERE (Team = @localTeam OR Opp = @localTeam) AND (Team = @localOpp OR Opp = @localOpp)
AND 结果 = 1)</p>
<p>设置@TeamResult = (SELECT COUNT(*) 来自 TeamHistoryMatchUps
WHERE Team = @localTeam 和 Opp = @localOpp
AND 结果 = 1)</p>
<p>SELECT (@TeamResult * 100 / @TotalResult) AS 百分比</p>
<p>exit_proc:
结束
***从未在 Azure DB 上尝试过这个