Sql 非常慢的存储过程
我很难进行查询优化,目前我非常接近数据库重新设计的阶段。这是我最后的希望。我认为仅仅显示查询是不够的,所以我不仅链接了数据库脚本,还附加了数据库备份,以防您不想手动生成数据 您可以找到脚本和备份 当您尝试执行以下操作时,问题开始出现Sql 非常慢的存储过程,sql,sql-server,stored-procedures,sql-server-2008-r2,sql-optimization,Sql,Sql Server,Stored Procedures,Sql Server 2008 R2,Sql Optimization,我很难进行查询优化,目前我非常接近数据库重新设计的阶段。这是我最后的希望。我认为仅仅显示查询是不够的,所以我不仅链接了数据库脚本,还附加了数据库备份,以防您不想手动生成数据 您可以找到脚本和备份 当您尝试执行以下操作时,问题开始出现 exec LockBranches @count=64,@lockedBy='034C0396-5C34-4DDA-8AD5-7E43B373AE5A',@lockedOn='2011-07-01 01:29:43.863',@unlockOn='2011-07-0
exec LockBranches @count=64,@lockedBy='034C0396-5C34-4DDA-8AD5-7E43B373AE5A',@lockedOn='2011-07-01 01:29:43.863',@unlockOn='2011-07-01 01:32:43.863'
这一部分出现的主要问题是:
UPDATE B
SET B.LockedBy = @lockedBy,
B.LockedOn = @lockedOn,
B.UnlockOn = @unlockOn,
B.Complete = 1
FROM
(
SELECT TOP (@count) B.LockedBy, B.LockedOn, B.UnlockOn, B.Complete
FROM Objectives AS O
INNER JOIN Generations AS G ON G.ObjectiveID = O.ID
INNER JOIN Branches AS B ON B.GenerationID = G.ID
INNER JOIN
(
SELECT SB.BranchID AS BranchID, SUM(X.SuitableProbes) AS SuitableProbes
FROM SpicieBranches AS SB
INNER JOIN Probes AS P ON P.SpicieID = SB.SpicieID
INNER JOIN
(
SELECT P.ID, 1 AS SuitableProbes
FROM Probes AS P
/* ----> */ INNER JOIN Results AS R ON P.ID = R.ProbeID /* SSMS Estimated execution plan says this operation is the roughest */
GROUP BY P.ID
HAVING COUNT(R.ID) > 0
) AS X ON P.ID = X.ID
GROUP BY SB.BranchID
) AS X ON X.BranchID = B.ID
WHERE
(O.Active = 1)
AND (B.Sealed = 0)
AND (B.GenerationNo < O.BranchGenerations)
AND (B.LockedBy IS NULL OR DATEDIFF(SECOND, B.UnlockOn, GETDATE()) > 0)
AND (B.Complete = 1 OR X.SuitableProbes = O.BranchSize * O.EstimateCount * O.ProbeCount)
) AS B
两个uniqueidentifier列上的连接似乎是问题的根源。一个是聚集索引,另一个是FK表上的非聚集索引。很好,上面有索引。不幸的是,当连接大量行时,guid的性能非常差 作为故障排除步骤: 索引处于什么状态?上次更新统计数据是什么时候? 当临时执行时,子查询自身的性能如何?i、 e.当您单独运行此语句时,resultset的返回速度有多快?可以接受吗? 重建两个指标并更新统计数据后,是否存在可测量的差异?
这基本上是一个完整的猜测,但在过去我发现连接到子查询的结果可能非常慢。也就是说,子查询被求值的次数太多了,而实际上它并不需要求值。
解决这个问题的方法是将子查询移动到CTE中,然后连接到CTE中。祝你好运 其他人可能比我能更好地解释为什么这要快得多。经验告诉我,如果有一堆查询一起运行得很慢,但在它们各自的部分应该很快,那么尝试一个临时表是值得的 这要快得多
ALTER PROCEDURE LockBranches
-- Add the parameters for the stored procedure here
@count INT,
@lockedOn DATETIME,
@unlockOn DATETIME,
@lockedBy UNIQUEIDENTIFIER
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON
--Create Temp Table
SELECT SpicieBranches.BranchID AS BranchID, SUM(X.SuitableProbes) AS SuitableProbes
INTO #BranchSuitableProbeCount
FROM SpicieBranches
INNER JOIN Probes AS P ON P.SpicieID = SpicieBranches.SpicieID
INNER JOIN
(
SELECT P.ID, 1 AS SuitableProbes
FROM Probes AS P
INNER JOIN Results AS R ON P.ID = R.ProbeID
GROUP BY P.ID
HAVING COUNT(R.ID) > 0
) AS X ON P.ID = X.ID
GROUP BY SpicieBranches.BranchID
UPDATE B SET
B.LockedBy = @lockedBy,
B.LockedOn = @lockedOn,
B.UnlockOn = @unlockOn,
B.Complete = 1
FROM
(
SELECT TOP (@count) Branches.LockedBy, Branches.LockedOn, Branches.UnlockOn, Branches.Complete
FROM Objectives
INNER JOIN Generations ON Generations.ObjectiveID = Objectives.ID
INNER JOIN Branches ON Branches.GenerationID = Generations.ID
INNER JOIN #BranchSuitableProbeCount ON Branches.ID = #BranchSuitableProbeCount.BranchID
WHERE
(Objectives.Active = 1)
AND (Branches.Sealed = 0)
AND (Branches.GenerationNo < Objectives.BranchGenerations)
AND (Branches.LockedBy IS NULL OR DATEDIFF(SECOND, Branches.UnlockOn, GETDATE()) > 0)
AND (Branches.Complete = 1 OR #BranchSuitableProbeCount.SuitableProbes = Objectives.BranchSize * Objectives.EstimateCount * Objectives.ProbeCount)
) AS B
END
然后你可以把它降到15毫秒,这比我们开始时好400倍。查看执行计划可以发现临时表上正在进行表扫描。通常情况下,您会尽可能避免表扫描,但对于128行,在这种情况下,它比以前做的任何操作都要快。在我的系统上,以下运行速度大约快15倍:
UPDATE B
SET B.LockedBy = @lockedBy,
B.LockedOn = @lockedOn,
B.UnlockOn = @unlockOn,
B.Complete = 1
FROM
(
SELECT TOP (@count) B.LockedBy, B.LockedOn, B.UnlockOn, B.Complete
FROM Objectives AS O
INNER JOIN Generations AS G ON G.ObjectiveID = O.ID
INNER JOIN Branches AS B ON B.GenerationID = G.ID
INNER JOIN
(
SELECT SB.BranchID AS BranchID, COUNT(*) AS SuitableProbes
FROM SpicieBranches AS SB
INNER JOIN Probes AS P ON P.SpicieID = SB.SpicieID
WHERE EXISTS(SELECT * FROM Results AS R WHERE R.ProbeID = P.ID)
GROUP BY SB.BranchID
) AS X ON X.BranchID = B.ID
WHERE
(O.Active = 1)
AND (B.Sealed = 0)
AND (B.GenerationNo < O.BranchGenerations)
AND (B.LockedBy IS NULL OR DATEDIFF(SECOND, B.UnlockOn, GETDATE()) > 0)
AND (B.Complete = 1 OR X.SuitableProbes = O.BranchSize * O.EstimateCount * O.ProbeCount)
) AS B
将子查询插入本地临时表
SELECT SB.BranchID AS BranchID, SUM(X.SuitableProbes) AS SuitableProbes
into #temp FROM SpicieBranches AS SB
INNER JOIN Probes AS P ON P.SpicieID = SB.SpicieID
INNER JOIN
(
SELECT P.ID, 1 AS SuitableProbes
FROM Probes AS P
/* ----> */ INNER JOIN Results AS R ON P.ID = R.ProbeID /* SSMS Estimated execution plan says this operation is the roughest */
GROUP BY P.ID
HAVING COUNT(R.ID) > 0
) AS X ON P.ID = X.ID
GROUP BY SB.BranchID
下面的查询显示与相应表的部分联接,而不是完整联接
UPDATE B
SET B.LockedBy = @lockedBy,
B.LockedOn = @lockedOn,
B.UnlockOn = @unlockOn,
B.Complete = 1
FROM
(
SELECT TOP (@count) B.LockedBy, B.LockedOn, B.UnlockOn, B.Complete
From
(
SELECT ID, BranchGenerations, (BranchSize * EstimateCount * ProbeCount) as MultipliedFactor
FROM Objectives AS O WHERE (O.Active = 1)
)O
INNER JOIN Generations AS G ON G.ObjectiveID = O.ID
Inner Join
(
Select Sealed, GenerationNo, LockedBy, UnlockOn, ID, Complete
From Branches
Where B.Sealed = 0 AND (B.LockedBy IS NULL OR DATEDIFF(SECOND, B.UnlockOn, GETDATE()) > 0)
)B ON B.GenerationID = G.ID
INNER JOIN
(
Select * from #temp
) AS X ON X.BranchID = B.ID
WHERE
AND (B.GenerationNo < O.BranchGenerations)
AND (B.Complete = 1 OR X.SuitableProbes = O.MultipliedFactor)
) AS B
已尝试还原,但没有R2取消。表中分别有多少行是Results和probe?我编辑了这个问题,以显示rowsSqlServer Profiler为CPU/Reads/Writes/Duration提供的大约6300/500000/670/8100的行数。所有索引都被重建和重新组织。每一个都有<20%的碎片,统计数据根本没有更新,不了解第二步。据我所知,这两个索引都应该集群化还是不集群化?请原谅我滥用了你的命名约定。我发现当所有的东西都有别名时,SQL真的很难阅读。嗨,大卫,这真的很奇怪,它的工作速度真的非常快,我不明白它是怎么发生的。。。关于约定不是问题,如果您愿意,请使用您自己的……也通过我的解决方案:,连接不是100%,它只是到所需的扩展。因此,影响了表扫描和执行计划中的其他内容……除了几个语法差异之外,这与我上面给出的解决方案相同。很高兴看到我们的想法是一致的。我重复一下,在我的例子中,连接不是100%,只是达到了所需的扩展。
UPDATE B
SET B.LockedBy = @lockedBy,
B.LockedOn = @lockedOn,
B.UnlockOn = @unlockOn,
B.Complete = 1
FROM
(
SELECT TOP (@count) B.LockedBy, B.LockedOn, B.UnlockOn, B.Complete
FROM Objectives AS O
INNER JOIN Generations AS G ON G.ObjectiveID = O.ID
INNER JOIN Branches AS B ON B.GenerationID = G.ID
INNER JOIN
(
SELECT SB.BranchID AS BranchID, COUNT(*) AS SuitableProbes
FROM SpicieBranches AS SB
INNER JOIN Probes AS P ON P.SpicieID = SB.SpicieID
WHERE EXISTS(SELECT * FROM Results AS R WHERE R.ProbeID = P.ID)
GROUP BY SB.BranchID
) AS X ON X.BranchID = B.ID
WHERE
(O.Active = 1)
AND (B.Sealed = 0)
AND (B.GenerationNo < O.BranchGenerations)
AND (B.LockedBy IS NULL OR DATEDIFF(SECOND, B.UnlockOn, GETDATE()) > 0)
AND (B.Complete = 1 OR X.SuitableProbes = O.BranchSize * O.EstimateCount * O.ProbeCount)
) AS B
SELECT SB.BranchID AS BranchID, SUM(X.SuitableProbes) AS SuitableProbes
into #temp FROM SpicieBranches AS SB
INNER JOIN Probes AS P ON P.SpicieID = SB.SpicieID
INNER JOIN
(
SELECT P.ID, 1 AS SuitableProbes
FROM Probes AS P
/* ----> */ INNER JOIN Results AS R ON P.ID = R.ProbeID /* SSMS Estimated execution plan says this operation is the roughest */
GROUP BY P.ID
HAVING COUNT(R.ID) > 0
) AS X ON P.ID = X.ID
GROUP BY SB.BranchID
UPDATE B
SET B.LockedBy = @lockedBy,
B.LockedOn = @lockedOn,
B.UnlockOn = @unlockOn,
B.Complete = 1
FROM
(
SELECT TOP (@count) B.LockedBy, B.LockedOn, B.UnlockOn, B.Complete
From
(
SELECT ID, BranchGenerations, (BranchSize * EstimateCount * ProbeCount) as MultipliedFactor
FROM Objectives AS O WHERE (O.Active = 1)
)O
INNER JOIN Generations AS G ON G.ObjectiveID = O.ID
Inner Join
(
Select Sealed, GenerationNo, LockedBy, UnlockOn, ID, Complete
From Branches
Where B.Sealed = 0 AND (B.LockedBy IS NULL OR DATEDIFF(SECOND, B.UnlockOn, GETDATE()) > 0)
)B ON B.GenerationID = G.ID
INNER JOIN
(
Select * from #temp
) AS X ON X.BranchID = B.ID
WHERE
AND (B.GenerationNo < O.BranchGenerations)
AND (B.Complete = 1 OR X.SuitableProbes = O.MultipliedFactor)
) AS B