Question

J'essaie de trouver un moyen simple d'améliorer les performances des forums très actifs où il y a un grand nombre de messages et où MySQL ne peut plus effectuer de tri de tables en mémoire et ne semble pas tirer pleinement parti des index.

Cette simple requête recherche le message le plus récent dans chaque sujet pour qu'un utilisateur puisse déterminer s'il a reçu des réponses depuis (en comparant ultérieurement le topic_time).

SELECT p.*, MAX(post_time) as post_time FROM forum_posts AS p   
WHERE p.poster_id = '1' AND p.post_status = '0' 
GROUP BY p.topic_id  
ORDER BY post_time DESC 
LIMIT 50

une table simple et plate ressemble à quelque chose

post_id | poster_id | topic_id | post_status | post_time | post_text

Cependant, ses performances s'effondrent lorsqu'il y a un million de publications et que l'utilisateur lui-même a des dizaines de milliers de publications.MySQL ne peut plus trier la table en mémoire ou il y a beaucoup trop de lignes à analyser.Cela peut prendre jusqu'à 3 secondes en utilisation réelle, ce qui est inacceptable à mon humble avis, car cela augmente le processeur pendant ce temps et ralentit tout le monde.

Je peux bien sûr créer n'importe quelle combinaison d'index, mais MySQL semble surtout utiliser une combinaison de

poster_id + post_time 

Il sélectionne donc simplement les 50 000 publications d'un utilisateur sur un million, puis commence à les regrouper par topic_id et à les trier.Étrangement, l'ajout de topic_id dans le mélange d'index ne semble pas améliorer les performances, même si cela peut être dû à l'ordre des champs d'index ?

J'ai essayé d'écrire un JOIN équivalent à la place pour pouvoir utiliser plus d'un index, mais je rencontre des problèmes avec le fait que chaque côté doit être filtré par post_status et poster.

Je pensais que ce serait plus rapide, au moins pour les premières pages, si MySQL pouvait être amené à trier d'abord les données via son index par post_time, puis à commencer à choisir le topic_id distinct pour l'utilisateur par ordre décroissant.Je suppose que cela nécessiterait une sous-requête et je ne suis pas sûr qu'une sous-requête de résultat de 50 000 serait meilleure, elle nécessite toujours une table temporaire.

Bien sûr, une solution fondamentale serait d'augmenter la conception de base afin qu'il y ait une autre table qui stocke simplement le post_time maximum pour chaque utilisateur dans chaque sujet, mais c'est un changement beaucoup trop important à moins qu'aucune autre solution ne puisse être trouvée.

Merci pour toutes suggestions!


ajouter un exemple réel et EXPLIQUER :

journal lent

# Query_time: 2.751334  Lock_time: 0.000056 Rows_sent: 40  Rows_examined: 48286
SELECT   p.*, MAX(post_time) as post_time FROM forum_posts AS p   WHERE p.poster_id = '2' AND p.post_status = '0' GROUP BY p.topic_id  ORDER BY post_time DESC LIMIT 7000, 40;

expliquer

select_type     table   type    possible_keys   key     key_len     ref     rows    Extra
SIMPLE          p   ref poster_time poster_time 4   const   27072   Using where; Using temporary; Using filesort
Était-ce utile?

La solution

Tout d’abord, corrigez votre requête pour fournir des résultats déterminés :

SELECT p.topic_id, 
       MAX(post_time) as post_time 
FROM forum_posts AS p   
WHERE p.poster_id = '1' AND p.post_status = '0' 
GROUP BY p.topic_id  
ORDER BY post_time DESC 
  LIMIT 50 ;

Ensuite, essayez-le après avoir ajouté un index sur (post_status, poster_id, topic_id, post_time).

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top