3 votes

TSQL plus rapide dans une boucle de curseur

Construire une requête.

La requête unique est présentée ci-dessous et s'exécute en 7,0 secondes. Elle renvoie la bonne réponse. J'ai besoin de compter les lignes en fonction de certaines conditions, puis d'obtenir le nombre maximum. Mon problème est la performance de cette requête indépendante. Cette même requête enveloppée dans un curseur s'exécute en 0,15 seconde. Dans le curseur, le plan de requête est très différent. Comment puis-je faire en sorte que la requête autonome s'exécute plus rapidement ?

En utilisant des astuces, j'ai pu faire en sorte que le plan autonome ressemble au plan du curseur et cela a réglé le problème de vitesse.

Correction de la requête : (pas entièrement corrigée car l'OPTION échoue)

select max(list.match) as 'max'
  from
  (
      SELECT 
       count(*) as 'match'  
      FROM [docSVenum1] with (nolock)   
      INNER LOOP JOIN  [FTSindexWordOnce] as w1 with (NOLOCK, FORCESEEK) 
        ON [docSVenum1].sID = w1.[sID] and [docSVenum1].[enumID] = '142'
      INNER HASH JOIN [FTSindexWordOnce] as w2 with (NOLOCK)
        ON  w1.wordID = w2.wordID and w2.[sID] = '2'      
      GROUP BY W1.[sID]
      -- OPTION (HASH GROUP)
  ) as list;

demande de problèmes :

select getdate();
go
  select max(list.match) as 'max'
  from
  (
      SELECT 
       count(*) as 'match'
      FROM [FTSindexWordOnce] as w1 with (nolock)
      INNER JOIN [docSVenum1] with (nolock)
        ON [docSVenum1].sID = w1.[sID] and [docSVenum1].[enumID] = '142'
      INNER JOIN [FTSindexWordOnce] as w2 with (nolock)
        ON  w1.wordID = w2.wordID AND w2.[sID] = '2'
      GROUP BY W1.[sID]
  ) as list;
go
select getdate();   -- 7.0 seconds

J'ai également besoin d'exécuter cette requête unique sur plusieurs valeurs et de la placer dans un curseur avec une boucle. Je sais que le curseur n'est pas une bonne solution, mais je n'ai pas réussi à trouver comment le faire sans curseur.

La requête seule et celle à l'intérieur de la boucle renvoient toutes deux la même réponse correcte.

Ma surprise est que la même requête dans une boucle de curseur est 40 fois plus rapide.

DECLARE @sid int

DECLARE sID_cursor CURSOR FOR 
SELECT top 80 sID
FROM docSVsys
WHERE sID = '2'  -- actually I want to not have this and let it loop through all
                 -- when i built the loop i saw performance improvement
ORDER BY sID

OPEN sID_cursor

FETCH NEXT FROM sID_cursor
INTO @sID

WHILE @@FETCH_STATUS = 0
BEGIN
    PRINT @sID

  select max(list.match) as 'max'
  from
  (
      SELECT 
       count(*) as 'match'
      FROM [FTSindexWordOnce] as w1 with (nolock)
      INNER JOIN [docSVenum1] with (nolock)
        ON [docSVenum1].sID = w1.[sID] and [docSVenum1].[enumID] = '142'
      INNER JOIN [FTSindexWordOnce] as w2 with (nolock)
        ON  w1.wordID = w2.wordID AND w2.[sID] = @sID
      GROUP BY W1.[sID]
  ) as list

    FETCH NEXT FROM sID_cursor
    INTO @sID

END 
CLOSE sID_cursor;
DEALLOCATE sID_cursor;
go
select getdate();  -- 0.15 seconds

1voto

Blam Points 17325

En utilisant des astuces, j'ai pu faire en sorte que le plan autonome ressemble au plan du curseur et cela a réglé le problème de vitesse.

Requête corrigée : (pas entièrement corrigée car l'OPTION échoue)

select max(list.match) as 'max'
  from
  (
      SELECT 
       count(*) as 'match'  
      FROM [docSVenum1] with (nolock)   
      INNER LOOP JOIN  [FTSindexWordOnce] as w1 with (NOLOCK, FORCESEEK) 
        ON [docSVenum1].sID = w1.[sID] and [docSVenum1].[enumID] = '142'
      INNER HASH JOIN [FTSindexWordOnce] as w2 with (NOLOCK)
        ON  w1.wordID = w2.wordID and w2.[sID] = '2'      
      GROUP BY W1.[sID]
      -- OPTION (HASH GROUP)
  ) as list;

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X