我正在使用一個存儲過程,它爲SystemTree
表中的所有可用節點生成等級。SQL Server存儲過程需要優化
我的存儲過程工作得很好,但問題是執行時間太長。
下面是表的詳細信息:
SystemTree
- 14000+行PaymentSchedule
- 5000+行MasterRankChart
- 只有15行
我需要優化我的存儲過程。至少需要20分鐘才能執行。
這是我的存儲過程:
ALTER PROCEDURE[dbo].[RankGeneration]
@CreatedUser nvarchar(128),
@CreatedOn datetime
AS
BEGIN
DECLARE @NodeKeyId nvarchar(128)
DECLARE MY_CURSOR CURSOR LOCAL STATIC READ_ONLY FORWARD_ONLY FOR
SELECT TOP 1000 NodeKeyId
FROM SystemTree
DECLARE @RankContainer TABLE
(
NodeKeyId nvarchar(128),
[Rank] nvarchar(512),
RankId int,
[LargestLeg] nvarchar(128),
[LargestLegNV] decimal(18, 2),
[SecondLargestLeg] nvarchar(128),
[SecondLargestLegNV] decimal(18, 2),
[ThirdPlusLeg] nvarchar(max),
[ThirdPlusLegNV] decimal(18, 2)
)
OPEN MY_CURSOR
FETCH NEXT FROM MY_CURSOR INTO @NodeKeyId
WHILE @@FETCH_STATUS = 0
BEGIN
DECLARE @YearlyMinPNV bigint
DECLARE @CurrentNodeId nvarchar(128)
DECLARE @TempNodeKeyId nvarchar(128)
DECLARE @TempChildKeyId nvarchar(128)
DECLARE @TempParentKeyId nvarchar(128)
DECLARE @TempPlacementNode hierarchyid
DECLARE @IMMEDIATEIDs TABLE
(
NodeKeyId nvarchar(128),
PlacementNode hierarchyid
)
INSERT INTO @IMMEDIATEIDs
SELECT NodeKeyId, PlacementNode
FROM SystemTree
WHERE PlacementNode.GetAncestor(1) = (SELECT PLACEMENTNODE
FROM SystemTree
WHERE NodeKeyId = @NodeKeyId)
DECLARE @ChildIDs TABLE
(
ParentNodeId nvarchar(128),
NodeKeyId nvarchar(128)
)
DECLARE @FinalNV TABLE
(
ParentNodeId nvarchar(128),
NodeKeyId nvarchar(128),
TotalNV decimal(18, 2)
)
DECLARE @ResultNV TABLE
(
ImmediateNodeID nvarchar(128),
TotalNV decimal(18, 2)
)
DECLARE @StorageNV TABLE
(
NodeKeyId nvarchar(128),
NV decimal(18, 2)
)
INSERT INTO @StorageNV
SELECT NodeKeyId, SUM(NV)
FROM PaymentSchedule
WHERE ClearDate IS NOT NULL
AND NV IS NOT NULL
GROUP BY NodeKeyId
DECLARE @i INT
DECLARE @count INT
SET @i = 0
SELECT @count = COUNT(*)
FROM @IMMEDIATEIDs
WHILE @i < @count
BEGIN
SELECT
@TempNodeKeyId = NodeKeyId,
@TempPlacementNode = PlacementNode
FROM
@IMMEDIATEIDs
ORDER BY
NodeKeyId
OFFSET (@i) ROWS FETCH NEXT 1 ROWS ONLY
INSERT @ChildIDs
SELECT
@TempNodeKeyId AS ParentNodeId,
t.NodeKeyId
FROM SystemTree t
WHERE PlacementNode.IsDescendantOf(@TempPlacementNode) = 1
AND t.NodeKeyId IN (SELECT NodeKeyId
FROM @StorageNV)
SET @i = @i + 1
END
SET @i = 0
SELECT @count = COUNT(*)
FROM @ChildIDs
WHILE @i < @count
BEGIN
SELECT
@TempChildKeyId = NodeKeyId,
@TempParentKeyId = ParentNodeId
FROM
@ChildIDs
ORDER BY
NodeKeyId
OFFSET (@i) ROWS FETCH NEXT 1 ROWS ONLY
INSERT INTO @FinalNV
VALUES(@TempParentKeyId, @TempChildKeyId,
(SELECT SUM(NV)
FROM @StorageNV
WHERE NodeKeyId = @TempChildKeyId));
SET @i = @i + 1
END
INSERT INTO @ResultNV
SELECT ParentNodeId, SUM(TotalNV)
FROM @FinalNV
GROUP BY ParentNodeId
DECLARE @MainCheckResult decimal(18, 2);
DECLARE @LargestLeg nvarchar(128);
DECLARE @MiddleCheckResult decimal(18, 2);
DECLARE @SecondLargestLeg nvarchar(128);
DECLARE @ThirdCheckResult decimal(18, 2);
DECLARE @ThirdPlusLeg nvarchar(128) = NULL;
SET @MainCheckResult = ISNULL((SELECT TOP(1) TotalNV
FROM @ResultNV
ORDER BY TotalNV DESC), 0);
SET @LargestLeg = (SELECT TOP(1) ImmediateNodeID
FROM @ResultNV
ORDER BY TotalNV DESC)
SET @MiddleCheckResult = ISNULL((SELECT TOP(1) TotalNV
FROM @ResultNV
WHERE ImmediateNodeID NOT IN (SELECT TOP(1) ImmediateNodeID
FROM @ResultNV
ORDER BY TotalNV DESC)
ORDER BY TotalNV DESC), 0);
SET @SecondLargestLeg = (SELECT TOP(1) ImmediateNodeID
FROM @ResultNV
WHERE ImmediateNodeID NOT IN (SELECT TOP (1) ImmediateNodeID
FROM @ResultNV
ORDER BY TotalNV DESC)
ORDER BY TotalNV DESC)
SET @ThirdCheckResult = ISNULL((SELECT SUM(TotalNV)
FROM @ResultNV
WHERE ImmediateNodeID NOT IN (SELECT TOP(2) ImmediateNodeID
FROM @ResultNV
ORDER BY TotalNV DESC)), 0);
SET @ThirdPlusLeg = NULL;
INSERT INTO @RankContainer
SELECT TOP(1)
@NodeKeyId AS NodeKeyId,
[Rank],
Id AS RankId,
@LargestLeg AS [LargestLeg],
@MainCheckResult AS [LargestLegNV],
@SecondLargestLeg AS [SecondLargestLeg],
@MiddleCheckResult AS [SecondLargestLegNV],
@ThirdPlusLeg AS [ThirdPlusLeg],
@ThirdCheckResult AS [ThirdPlusLegNV]
FROM
MasterRankChart
WHERE
LargestLegNV + SecondLegNV + ThirdLegNV <= @MainCheckResult + @MiddleCheckResult + @ThirdCheckResult
AND SecondLegNV + ThirdLegNV <= @MiddleCheckResult + @ThirdCheckResult
AND ThirdLegNV <= @ThirdCheckResult
ORDER BY
Priority
FETCH NEXT FROM MY_CURSOR INTO @NodeKeyId
END
CLOSE MY_CURSOR
DEALLOCATE MY_CURSOR
MERGE TrackRank AS Target
USING(SELECT
NodeKeyID, [Rank], [RankId],
[LargestLeg], [LargestLegNv],
SecondLargestLeg, SecondLargestLegNV,
ThirdPlusLeg, ThirdPlusLegNV
FROM @RankContainer) AS Source ON (Target.NodeKeyId = Source.NodeKeyId)
WHEN MATCHED THEN
UPDATE
SET Target.[Rank] = Source.[Rank],
Target.[RankId] = Source.[RankId],
Target.[LargestLeg] = Source.[LargestLeg],
Target.[LargestLegNv] = Source.[LargestLegNv],
Target.SecondLargestLeg = Source.SecondLargestLeg,
Target.SecondLargestLegNV = Source.SecondLargestLegNV,
Target.ThirdPlusLeg = Source.ThirdPlusLeg,
Target.ThirdPlusLegNV = Source.ThirdPlusLegNV
WHEN NOT MATCHED BY TARGET THEN
INSERT (NodeKeyId, [Rank], [RankId], LargestLeg, LargestLegNV,
SecondLargestLeg, SecondLargestLegNV,
ThirdPlusLeg, ThirdPlusLegNV,
CreatedOn, UpdatedOn, IsDeleted, CreatedBy)
VALUES (Source.NodeKeyID, Source.[Rank], Source.[RankId],
Source.[LargestLeg], Source.[LargestLegNv],
Source.SecondLargestLeg, Source.SecondLargestLegNV,
Source.ThirdPlusLeg, Source.ThirdPlusLegNV,
@CreatedOn, @CreatedOn, 0, @CreatedUser)
OUTPUT $ACTION, INSERTED.*, DELETED.*;
END
請看一看任何給我建議,我該如何優化它。
感謝&問候,
GO先生
感謝您的建議,一定會對它有所幫助。 –