2015-03-25 1 views
0

Je travaille sur l'optimisation d'une procédure, actuellement il faut un peu plus de 23 minutes pour exécuter à partir de SQL. J'ai essayé de réindexer mes tables et cela n'a montré aucun signe d'amélioration.Existe-t-il un moyen d'accélérer une requête complexe avec 3x UNION All sur la même grande table?

Je n'ai pas été en mesure de trouver un moyen de nous appliquer une croix ou UNPIVOT pour que cela fonctionne bien.

Y at-il quelque chose que je pourrais faire pour améliorer la vitesse de cette procédure?

@ClientId int, 
    @FormParentId int = NULL, 
    @FormQueryMode varchar(20) = 'changelog' 
declare 
    @ClientId int, 
    @FormParentId INT, 
    @FormQueryMode varchar(20) 

select 
     @ClientId = 11, 
     @FormParentId = 277719, 
     @FormQueryMode = NULL 

DROP TABLE #History 
*/ 
    CREATE TABLE #History 
    (
     FormHistRecId bigint IDENTITY(1,1) NOT NULL, 
     FormParentId int, 
     EffDate datetime, 
     Updated datetime NULL, 
     Change varchar(50), 
     VersionNote varchar(1000), 
     VersionUserId varchar(50) 
    ) 

    INSERT INTO #History (FormParentId, EffDate, Updated, Change, VersionNote, VersionUserId) 
    SELECT ParentId, EffDate, Updated, Change, VersionNote, VersionUserId 
    FROM (
     SELECT f.ClientId, CASE WHEN f.MainFormId IS NULL THEN f.ParentId ELSE (SELECT ParentId FROM Forms WHERE FormId=f.MainFormId) END AS ParentId, f.EffDate, f.Updated, 'Forms' as Change, 
      f.VersionNote, f.VersionUserId 
     FROM Forms f 
     WHERE Status IN (0,1,2) --negatives are 'temporary', and should be ignored if they aren't already cleaned out 
     UNION ALL/* 
     SELECT f.ClientId, (SELECT ParentId FROM Forms WHERE FormId=f.MainFormId) AS ParentId, f.EffDate, f.Updated, 'Attachment_Forms' as Change, 
      f.VersionNote, f.VersionUserId 
     FROM Forms f 
     WHERE Status IN (0,1,2) --negatives are 'temporary', and should be ignored if they aren't already cleaned out 
     UNION ALL*/ 
     SELECT f.ClientId, CASE WHEN f.MainFormId IS NULL THEN f.ParentId ELSE (SELECT ParentId FROM Forms WHERE FormId=f.MainFormId) END, h.EffDate, h.Updated, 'Holders' as Change, 'Holder Updated' as VersionNote, h.VersionUserId 
     FROM Forms f 
     LEFT OUTER JOIN Forms f_exp ON f_exp.FormId=(
      SELECT TOP 1 FormId 
      FROM Forms 
      WHERE ParentId=f.ParentId 
      AND (EffDate > f.EffDate OR (EffDate=f.EffDate AND Updated > f.Updated)) 
      ORDER BY EffDate ASC, Updated ASC 
     ) 
     --check for holder updates within the span this Forms record's selection implies 
     INNER JOIN Holders h ON h.ParentId=f.HolderParentId 
       AND h.EffDate >= f.EffDate --must be effective after-or-with the form 
       AND h.EffDate >= f.Updated --must be entered after-or-with the form 
       AND (f_exp.FormId IS NULL OR h.EffDate < f_exp.EffDate) --must be effective before next form becomes effective 
       AND (f_exp.FormId IS NULL OR h.EffDate < f_exp.Updated) --must be entered before next form is entered 
     UNION ALL 
     SELECT f.ClientId, CASE WHEN f.MainFormId IS NULL THEN f.ParentId ELSE (SELECT ParentId FROM Forms WHERE FormId=f.MainFormId) END, ct.Updated as EffDate, NULL AS Updated, 'ClientTemplates' as Change 
      ,ct.VersionNote, ct.VersionUserId 
     FROM Forms f 
     LEFT OUTER JOIN Forms f_exp ON f_exp.FormId=(
      SELECT TOP 1 FormId 
      FROM Forms 
      WHERE ParentId=f.ParentId 
      AND (EffDate > f.EffDate OR (EffDate=f.EffDate AND Updated > f.Updated)) 
      ORDER BY EffDate ASC, Updated ASC 
     ) 
     INNER JOIN ClientTemplates ct ON ct.ParentId=f.TemplateParentId 
       AND ct.Updated >= f.EffDate 
       --AND ct.Updated >= f.Updated 
       AND (f_exp.FormId IS NULL OR ct.Updated < f_exp.EffDate) 
       --AND (f_exp.FormId IS NULL OR ct.Updated < f_exp.Updated) 
     UNION ALL 
     SELECT f.ClientId, CASE WHEN f.MainFormId IS NULL THEN f.ParentId ELSE (SELECT ParentId FROM Forms WHERE FormId=f.MainFormId) END, mt.Updated as EffDate, NULL AS Updated, 'MasterTemplates' as Change 
      ,mt.VersionNote, mt.VersionUserId 
     FROM Forms f 
     LEFT OUTER JOIN Forms f_exp ON f_exp.FormId=(
      SELECT TOP 1 FormId 
      FROM Forms 
      WHERE ParentId=f.ParentId 
      AND (EffDate > f.EffDate OR (EffDate=f.EffDate AND Updated > f.Updated)) 
      ORDER BY EffDate ASC, Updated ASC 
     ) 
     INNER JOIN ClientTemplates ct ON ct.ParentId=f.TemplateParentId 
       AND ct.Updated >= f.EffDate 
       --AND ct.Updated >= f.Updated 
       AND (f_exp.FormId IS NULL OR ct.Updated < f_exp.EffDate) 
       --AND (f_exp.FormId IS NULL OR ct.Updated < f_exp.Updated) 
     LEFT OUTER JOIN ClientTemplates ct_exp ON ct_exp.TemplateId=(
      SELECT TOP 1 TemplateId 
      FROM ClientTemplates 
      WHERE ParentId=ct.ParentId 
      AND Updated > ct.Updated --(no eff date) 
      ORDER BY Updated ASC 
     ) 
     INNER JOIN MasterTemplates mt ON mt.ParentId=ct.MasterParentId 
       AND mt.Updated >= ct.Updated 
       --AND mt.Updated >= ct.Updated 
       AND (ct_exp.TemplateId IS NULL OR mt.Updated < ct_exp.Updated) 
     UNION ALL 
     SELECT (SELECT TOP 1 ClientId FROM Forms WHERE ParentId=ctblsel.FormParentId), 
      (SELECT 
      CASE WHEN f.MainFormId IS NULL THEN f.ParentId ELSE (SELECT ParentId FROM Forms WHERE FormId=f.MainFormId) END 
      FROM Forms f WHERE FormId=(
       SELECT TOP 1 FormId 
       FROM Forms 
       WHERE ParentId=ctblsel.FormParentId 
       AND (EffDate > ctblsel.EffDate OR (EffDate=ctblsel.EffDate AND Updated > ctblsel.Updated)) 
       ORDER BY EffDate DESC, Updated DESC 
       ) 
      )AS FormParentId, 
      --ctblsel.FormParentId, 
ctblsel.EffDate, ctblsel.Updated, 'CTblEntrySelection' as Change 
      ,'Client Table Entry Selected' as VersionNote, ctblsel.VersionUserId 
     FROM CTblEntrySelection ctblsel 
    ) dt 
    WHERE [email protected] 
    AND (@FormParentId IS NULL OR [email protected]) 

    DECLARE CTblCur CURSOR FOR 
    SELECT ClientTableId 
    FROM ClientTables 
    WHERE [email protected] 
    OPEN CTblCur 
    DECLARE @ClientTableId int 
    DECLARE @q nvarchar(MAX), @p nvarchar(100), @tblname nvarchar(50) 
    SET @p = 
'@ClientId int, 
@FormParentId int, 
@ClientTableId int' 
    FETCH NEXT FROM CTblCur INTO @ClientTableId 
    WHILE @@FETCH_STATUS = 0 
    BEGIN 
     SET @tblname = '[ClientTable_'+CONVERT(nvarchar,@ClientTableId)+']' 
     SET @q = 
'INSERT INTO #History (FormParentId, EffDate, Updated, Change, VersionNote, VersionUserId) 
SELECT ctblsel.FormParentId, ctbl.Updated as EffDate, NULL AS Updated, ''ClientTable'' as Change 
    ,ctbl.VersionNote, ctbl.VersionUserId 
FROM CTblEntrySelection ctblsel 
LEFT OUTER JOIN CTblEntrySelection ctblsel_exp ON ctblsel_exp.RecId = (
     SELECT TOP 1 RecId 
     FROM CTblEntrySelection 
     WHERE FormParentId=ctblsel.FormParentId 
     AND ClientTableId=ctblsel.ClientTableId 
     AND (EffDate > ctblsel.EffDate OR (EffDate=ctblsel.EffDate AND Updated > ctblsel.Updated)) 
     ORDER BY EffDate ASC, Updated ASC 
) 
INNER JOIN '[email protected]+' ctbl ON ctbl.ParentId=ctblsel.CTblEntryParentId 
     AND ctbl.Updated >= ctblsel.EffDate --must be effective after-or-with the form 
     --AND ctbl.Updated >= ctblsel.Updated --must be entered after-or-with the form 
     AND (ctblsel_exp.RecId IS NULL OR ctbl.Updated < ctblsel_exp.EffDate) --must be effective before next form becomes effective 
     --AND (ctblsel_exp.RecId IS NULL OR ctbl.Updated < ctblsel_exp.Updated) --must be entered before next form is entered 
WHERE (SELECT TOP 1 ClientId FROM Forms WHERE ParentId=ctblsel.FormParentId)[email protected] 
AND [email protected]' 
     IF @FormParentId IS NOT NULL 
      SET @q = @q + ' 
AND [email protected]' 
print @q 
     EXEC sp_ExecuteSql @q, @p, @ClientId, @FormParentId, @ClientTableId 
     FETCH NEXT FROM CTblCur INTO @ClientTableId 
    END 
    CLOSE CTblCur 
    DEALLOCATE CTblCur 

    IF @FormQueryMode = 'issuancelog' 
    BEGIN 
     INSERT INTO #History (FormParentId, EffDate, Updated, Change, VersionNote, VersionUserId) 
     SELECT l.FormParentId, l.EffDate, l.Updated, 'Issuance', h.VersionNote, l.UserId 
     FROM FormIssuanceLog l 
     LEFT OUTER JOIN #History h ON h.FormHistRecId=(
      SELECT TOP 1 FormHistRecId 
      FROM #History 
      WHERE FormParentId=l.FormParentId 
      AND EffDate <= l.EffDate 
      AND COALESCE(Updated,EffDate) <= l.Updated --if #history's Updated is null, means it's a change that cannot be anachronistic; updated = effective. 
      ORDER BY EffDate DESC, Updated DESC 
     ) 
     WHERE (
      (@FormParentId IS NOT NULL AND [email protected]) 
      OR 
      (@FormParentId IS NULL AND l.FormParentId IN (SELECT ParentId FROM Forms WHERE [email protected])) 
     ) 
     AND l.ConfirmIssued=1 

     DELETE FROM #History WHERE Change<>'Issuance' 
    END 

    SELECT *, 
     LastName + ', ' + FirstName + ' (' + Username + ')' as VersionAuthor 
    FROM (
     SELECT 
      'Courier' FormType, 
      dt2.FormParentId, 
      NULL as LegacyFormId, 
      dt2.EffDate, 
      dt2.Updated, 
      dt2.Change, 
      dt2.VersionNote, 
      dt2.VersionUserId 
      ,Forms.FormId, ClientTemplates.Name as CTName, Users.FirstName, Users.LastName, Users.Username 
      ,'Courier_'+CONVERT(nvarchar,dt2.FormParentId)+'_'+CONVERT(nvarchar,dt2.EffDate,127)+COALESCE('_'+CONVERT(nvarchar,dt2.Updated,127),'') as PK 
      ,CASE Change 
       WHEN 'MasterTemplates' THEN 'Master Form (blank PDF)' 
       WHEN 'ClientTemplates' THEN 'Template' 
       WHEN 'ClientTable' THEN 'Client Table' 
       WHEN 'Forms' THEN 'Form' 
       WHEN 'Holders' THEN 'Holder Address Record' 
       WHEN 'CTblEntrySelection' THEN 'Client Table Selection' 
       WHEN 'Issuance' THEN 'Form Issuance' 
       ELSE '-----' 
      END ChangeText 
      ,'pg_IssuanceLogPrompt' as Interface 
      ,CASE @FormQueryMode WHEN 'issuancelog' THEN 'ShowHistForm_IssMode' ELSE 'ShowHistForm' END as Command 
      ,CONVERT(varchar(50),dt2.FormParentId) as Param1 
      ,CONVERT(varchar(50),dt2.EffDate,126) Param2 
      ,CONVERT(varchar(50),dt2.Updated,126) Param3 
      ,'Courier.frm' AS HTTPTarget 
      ,Forms.Status FormStatus 
      ,ie.Name AS EditionName 
     FROM (
      SELECT *, ROW_NUMBER() OVER (PARTITION BY FormParentId, EffDate, Updated ORDER BY ChangeDominance ASC) rn 
      FROM (
       SELECT *, 
        CASE Change 
         WHEN 'MasterTemplates' THEN 1 
         WHEN 'ClientTemplates' THEN 2 
         WHEN 'ClientTable' THEN 3 
         WHEN 'Forms' THEN 4 
         WHEN 'Holders' THEN 5 
         WHEN 'CTblEntrySelection' THEN 6 
         ELSE 99 
        END as ChangeDominance --largely applies to change log; issuance log will get 99, but it only has one value anyway 
       FROM #History 
      ) dt 
     ) dt2 
     LEFT OUTER JOIN Forms ON Forms.FormId=(
      SELECT TOP 1 FormId 
      FROM Forms 
      WHERE ParentId=dt2.FormParentId 
      AND EffDate <= dt2.EffDate 
      AND Updated <= COALESCE(dt2.Updated, dt2.Updated) --if #history's Updated is null, means it's a change that cannot be anachronistic; updated = effective. 
      AND [Status] >= 0 
      ORDER BY EffDate DESC, Updated DESC 
     ) 
     LEFT OUTER JOIN Users ON Users.UserId=dt2.VersionUserId 
     LEFT OUTER JOIN ClientTemplates ON ClientTemplates.TemplateId=(
      SELECT TOP 1 TemplateId 
      FROM ClientTemplates 
      WHERE ParentId=Forms.TemplateParentId 
      AND Updated <= dt2.EffDate 
      --AND Updated <= dt2.Updated 
      ORDER BY Updated DESC 
     ) 
     LEFT OUTER JOIN dbo.IssuanceEditions ie ON ie.EditionId=(
      SELECT TOP 1 EditionId 
      FROM dbo.IssuanceEditions ie2 
      WHERE ie2.ClientId=(SELECT DISTINCT ClientId FROM dbo.Forms WHERE ParentId=dt2.FormParentId) 
      AND ie2.Updated <= dt2.EffDate 
      ORDER BY ie2.Updated DESC 
     )   
     WHERE rn=1 
     UNION ALL 
     SELECT 
      'LegacyPDF' as FormType, 
      NULL as FormParentId, 
      LegacyFormId, 
      EffDate, 
      NULL as Updated, 
      'Imported File' as Change, 
      HistDescription as VersionNote, 
      NULL as VersionUserId 
      ,NULL as FormId, NULL as CTName, NULL as FirstName, NULL as LastName, NULL as Username 
      ,'LegacyPDF_'+CONVERT(nvarchar,LegacyFormId) as PK 
      ,'Imported File' as ChangeText 
      ,'ShowLegacyForm' as Interface 
      ,'' as Command 
      ,CONVERT(varchar(50),LegacyFormId) as Param1 
      ,NULL Param2 
      ,NULL Param3 
      ,'Courier.dwnl' AS HTTPTarget 
      ,NULL FormStatus 
      ,NULL EditionName 
     FROM LegacyForms 
     WHERE [email protected] 
     AND (@FormParentId IS NULL OR [email protected]) 
    ) dt 
    ORDER BY EffDate DESC, Updated DESC 

Répondre

0

Le curseur saute comme quelque chose que vous pouvez vouloir supprimer. C'est une requête tellement vaste avec autant de pièces qu'il est presque impossible de voir où, et si, cela peut être amélioré.

Examinez les plans de requête générés par le lot et probablement une ou deux requêtes prendront 80% si le lot et ceux-ci doivent être examinés très attentivement. Je prédis que la plupart du temps est consacré à l'instruction sp_executesql et que, si possible, il doit être remplacé par une jointure que SQL Server peut optimiser.

+0

Merci pour vos conseils, je vais essayer. Il s'agit d'une ancienne requête qui fonctionne correctement pour un programme Web, mais qui provoque maintenant de nombreux problèmes. – MeyerEngineer

+0

Ce qui est probablement arrivé (devinant sauvagement ici ...) que le nombre de clients a augmenté de sorte que le curseur exécute beaucoup plus de fois ..... –

+0

c'est correct. Il y a plus de 3 000 tables clientes maintenant. J'ai dû commencer et créer une nouvelle base de données juste pour un client pour continuer à exécuter le programme. – MeyerEngineer