2010-05-24 7 views
1

Nous sommes en train d'installer un nouveau forum (yaf) pour notre site. L'une des procédures stockées est extrêmement lente - en fait, elle expire toujours dans le navigateur. Si je l'exécute dans MSSMS, cela prend près de 10 minutes. Existe-t-il un moyen de savoir quelle partie de cette requête prend si longtemps?Résoudre une requête lente

La requête:

DECLARE @BoardID int 
DECLARE @UserID int 
DECLARE @CategoryID int = null 
DECLARE @ParentID int = null 

SET @BoardID = 1 
SET @UserID = 2 

    select 
    a.CategoryID, 
    Category  = a.Name, 
    ForumID   = b.ForumID, 
    Forum   = b.Name, 
    Description, 
    Topics   = [dbo].[yaf_forum_topics](b.ForumID), 
    Posts   = [dbo].[yaf_forum_posts](b.ForumID), 
    Subforums  = [dbo].[yaf_forum_subforums](b.ForumID, @UserID), 
    LastPosted  = t.LastPosted, 
    LastMessageID = t.LastMessageID, 
    LastUserID  = t.LastUserID, 
    LastUser  = IsNull(t.LastUserName,(select Name from [dbo].[yaf_User] x where x.UserID=t.LastUserID)), 
    LastTopicID  = t.TopicID, 
    LastTopicName = t.Topic, 
    b.Flags, 
    Viewing   = (select count(1) from [dbo].[yaf_Active] x JOIN [dbo].[yaf_User] usr ON x.UserID = usr.UserID where x.ForumID=b.ForumID AND usr.IsActiveExcluded = 0), 
    b.RemoteURL, 
    x.ReadAccess 
from 
    [dbo].[yaf_Category] a 
    join [dbo].[yaf_Forum] b on b.CategoryID=a.CategoryID 
    join [dbo].[yaf_vaccess] x on x.ForumID=b.ForumID 
    left outer join [dbo].[yaf_Topic] t ON t.TopicID = [dbo].[yaf_forum_lasttopic](b.ForumID,@UserID,b.LastTopicID,b.LastPosted) 
where 
    a.BoardID = @BoardID and 
    ((b.Flags & 2)=0 or x.ReadAccess<>0) and 
    (@CategoryID is null or [email protected]) and 
    ((@ParentID is null and b.ParentID is null) or [email protected]) and 
    x.UserID = @UserID 
order by 
    a.SortOrder, 
    b.SortOrder 

IO Statistiques:

Table 'Worktable'. Scan count 0, logical reads 0, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0. 
Table 'yaf_Active'. Scan count 14, logical reads 28, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0. 
Table 'yaf_User'. Scan count 0, logical reads 3, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0. 
Table 'yaf_Topic'. Scan count 0, logical reads 0, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0. 
Table 'yaf_Category'. Scan count 0, logical reads 28, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0. 
Table 'yaf_Forum'. Scan count 0, logical reads 488, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0. 
Table 'yaf_UserGroup'. Scan count 231, logical reads 693, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0. 
Table 'Worktable'. Scan count 0, logical reads 0, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0. 
Table 'yaf_ForumAccess'. Scan count 1, logical reads 2, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0. 
Table 'yaf_AccessMask'. Scan count 1, logical reads 2, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0. 
Table 'yaf_UserForum'. Scan count 1, logical reads 0, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0. 

Statistiques clients:

Client Execution Time 11:54:01   
Query Profile Statistics    
    Number of INSERT, DELETE and UPDATE statements 0  0.0000 
    Rows affected by INSERT, DELETE, or UPDATE statements 0  0.0000 
    Number of SELECT statements 8  8.0000 
    Rows returned by SELECT statements 19  19.0000 
    Number of transactions 0  0.0000 
Network Statistics   
    Number of server roundtrips 3  3.0000 
    TDS packets sent from client 3  3.0000 
    TDS packets received from server 34  34.0000 
    Bytes sent from client 3166  3166.0000 
    Bytes received from server 128802  128802.0000 
Time Statistics   
    Client processing time 156478  156478.0000 
    Total execution time 572009  572009.0000 
    Wait time on server replies 415531  415531.0000 

Execution Plan

Répondre

5

Jetez un oeil à Do you use [email protected] OR @Param IS NULL in your WHERE clause? Don't, it doesn't perform pour avoir une idée de la façon de réécrire cela en utilisant sp_executesql qui fonctionnera mieux.

Cela ressemble également à un appel de fonction?

left outer join [dbo].[yaf_Topic] t ON t.TopicID = [dbo].[yaf_forum_lasttopic](b.ForumID,@UserID,b.LastTopicID,b.LastPosted) 

peut-être votre fonction est de déconner cette chose, hardcode quelque chose plutôt que l'appel de fonction et voir si cela fait une différence drastique

+0

Oui, c'était ça. Lancer un topicID aléatoire l'a fait s'exécuter en 271ms. Comment l'avez-vous resserré? – cschear

+1

Parce que je sais comment fonctionnent les fonctions ....... ils ne devraient en général pas être utilisés dans les clauses WHERE ou JOINs – SQLMenace

+0

Et parce que SQLMenace est génial, bien sûr. – HLGEM

2

Avec ce genre de statistiques d'entrées-sorties, la requête doit être b verrouillage. Pendant que le SP est en cours d'exécution, vérifiez sys.dm_exec_requests pour l'id session_id de votre procédure en cours d'exécution (le @@ SPID), et voyez blocking_session_id, wait_type, wait_time et wait_resource. Ceux-ci devraient vous guider vers la raison du blocage.

+0

Bien que cela n'a pas aidé avec cette requête qui sera certainement utilisée. Je vous remercie. – cschear

0

je remarqué ce tableau est votre plus grand IO coupable:

Table 'yaf_UserGroup'. nombre de balayage 231, lit logique 693, lit physique 0, lecture anticipée lit 0, lob logique lit 0, lit physique lob 0, lecture anticipée lobé lit 0.

J'ai aussi remarqué que la table incriminée est pas directement mentionné dans votre requête. Cela signifie qu'il doit être référencé dans l'une des fonctions UDF utilisées dans votre requête. Ma conjecture est que les UDF empêchent la requête d'utiliser efficacement les index sur votre table yaf_UserGroup. Vous pouvez corriger cela en fusionnant la logique du fichier UDF incriminé directement dans la requête.

Enfin, quel que soit le problème, il semble que yaf soit open source. Cela signifie que vous devez apporter votre correctif au projet d'origine. Cela vous sera utile en vous aidant à garder votre code plus en ligne avec le projet de base, de sorte qu'une future mise à jour n'annule pas votre solution de performance.

1

Je ne vois rien de mal dans votre plan d'exécution. Très probablement, une autre session verrouille votre requête ou votre serveur est sous une charge extrêmement lourde.

1

Les sous-requêtes corrélées sont exécutées ligne par ligne. Convertissez-les en jointures.

Même chose avec vos UDF. Les convertir en jointures devrait accélérer beaucoup les choses, car elles courent aussi rangée par rangée.

Et ce que SQL Menace a dit.

Questions connexes