2009-08-17 4 views
3

Je suppose qu'il s'agit d'un SP assez courant dans les réseaux sociaux et les sites Web de type communautaire. J'ai ce SP qui renvoie tous les amis d'un utilisateur sur leur page d'amis par ceux actuellement en ligne, puis par ordre alphabétique. Ça prend beaucoup de temps à charger et je cherche à l'accélérer. Je me souviens avoir lu quelque part sur SO que briser plusieurs jointures en ensembles de résultats plus petits pourrait l'accélérer. Je n'ai pas encore essayé, mais je suis curieux de voir quelles autres recommandations pourraient avoir sur cette procédure.Optimisation de cette requête. Pertinent pour les administrateurs de bases de données travaillant sur un site Web de type réseau social/communautaire

DECLARE @userID INT -- This variable is parsed in 
DECLARE @lastActivityMinutes INT 

SET @lastActivitytMinutes = '15' 

SELECT 
    Active = CASE WHEN DATEDIFF("n", b.LastActivityDate ,GETDATE()) < @lastActivityMinutes THEN 1 ELSE 0 END, 
    a.DisplayName, a.ImageFile, a.UserId, b.LastActivityDate 
FROM 
    Profile AS a 
     INNER JOIN aspnet_Users as b on b.userId = a.UserId 
     LEFT JOIN Friend AS x ON x.UserID = a.UserID 
     LEFT JOIN Friend AS z ON z.FriendID = a.UserID 
WHERE ((x.FriendId = @userID AND x.status = 1) -- Status = 1 means friendship accepted 
     OR (z.UserID = @userID AND z.Status = 1)) 
GROUP BY a.userID, a.DisplayName, a.ImageFile, a.UserId, b.LastActivityDate 
ORDER BY Active DESC, DisplayName ASC 

Je ne suis pas sûr de savoir comment clip dans mon plan d'exécution, mais le principal goulot de la bouteille semble se produire sur un MERGE JOIN (jointure externe droite) qui me coûte 29%. À différents stades, le parallélisme coûte également 9%, 6%, 5% et 9% pour un total de 29%. Mes réflexions initiales sont de retourner d'abord les résultats JOINTED des tables Profile et aspnet avec un CTE, puis de faire des JOINT LEFT à la table des amis.

Répondre

3

Vous joindrez Friend deux fois, en utilisant un LEFT JOIN, vous supprimez les NULL « s renvoyés par la LEFT JOIN par WHERE état, puis en utilisant GROUP BY pour se débarrasser de concepts distincts.

Ce n'est pas la meilleure requête possible.

Pourquoi ne pas utiliser tout ce que vous:

SELECT Active = CASE WHEN DATEDIFF("n", b.LastActivityDate ,GETDATE()) < @lastActivityMinutes THEN 1 ELSE 0 END, 
     a.DisplayName, a.ImageFile, a.UserId, b.LastActivityDate 
FROM (
     SELECT FriendID 
     FROM Friends 
     WHERE UserID = @UserId 
       AND status = 1 
     UNION 
     SELECT UserID 
     FROM Friends 
     WHERE FriendID = @UserId 
       AND status = 1 
     ) x 
INNER JOIN 
     Profile AS a 
ON  a.UserID = x.FriendID 
INNER JOIN 
     aspnet_Users as b 
ON  b.userId = a.UserId 
ORDER BY 
     Active DESC, DisplayName ASC 
+0

Oui, cela nous amène à mes premiers problèmes. Parfois, un utilisateur fait ou reçoit seulement 1 demande d'ami. Cela signifie que l'ID peut exister dans la colonne UserID ou FriendID de la table Friend. Faire des INNER JOIN comme celui que vous avez déclaré ne lui rendra pas son amitié. En utilisant votre script, ma sélection de retour est passée de 395 (mine) à 362 lignes. – super9

+0

@Nai: est-ce pour la nouvelle requête avec 'UNION ALL'? – Quassnoi

+0

Ceci est pour l'ancien. Avec celui-ci, il ne retourne aucune ligne. J'essaie actuellement de déterminer pourquoi – super9

Questions connexes