0

Je travaille avec une procédure stockée qui génère un rang pour tous les nœuds qui sont disponibles dans le tableau SystemTree.Procédure SQL Server stockée Optimisation requise

Ma procédure stockée fonctionne parfaitement, mais le problème est que l'exécution est trop longue.

Voici les détails de la table:

  • SystemTree - 14000+ lignes
  • PaymentSchedule - 5000+ lignes
  • MasterRankChart - seulement 15 lignes

je dois optimiser ma procédure stockée . Il faut au moins 20 minutes pour l'exécuter.

Ceci est ma procédure stockée:

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 

S'il vous plaît jeter un oeil tout me donner des suggestions que comment puis-je optimiser.

Merci & Cordialement,

M. GO

Répondre

1

Première Sugestion serait d'éviter CURSOR - chaque fois que lorsque vous pouvez éviter CURSOR, vous devriez le faire. Un autre conseil, jetez un oeil à plan d'exécution, peut-être vous willl être en mesure de détecter les goulots d'étranglement, etc.

+0

Appréciez vos suggestions, allez certainement travailler dessus. –

0

Ce qui suit sera utile pour optimiser le temps d'exécution de la requête:

  1. Essayez d'exécuter sans utiliser les curseurs
  2. Création d'un index sur les tables de référence
  3. Ouvrez SQL Server Profiler, puis exécutez la requête et enregistrez le fichier de trace dans l'outil Profiler. Ensuite, ouvrez ce fichier de trace (*.trc) dans l'Assistant Paramétrage de SQL Server et estimez-le, afin de nous aider à réduire le temps d'exécution.
+0

J'avais essayé votre chemin. Mais cela augmente mon temps d'exécution de 10 fois. –

+0

Oh !, Vraiment désolé @ Mr.Go, Pour ma requête, SQL Tuning Advisor a montré quelques points. J'ai suivi cela, je me sentais mieux, donc je vous ai conseillé. –