2010-11-28 23 views
0

Je souhaite implémenter une fonctionnalité très courante: filtrer certains éléments par tag. Il existe de nombreux tutoriels sur Internet avec des exemples de la façon de le faire. La requête est assez simple et rapide (en supposant que les index appropriés existent).
Mais généralement les éléments filtrés doivent être triés par un champ. Par exemple, lorsque vous filtrez les questions par tag sur SO, les résultats sont triés.Trier les éléments filtrés par le tag

Pour accomplir cette tâche (en supposant que nous devons trier par notes), on pourrait écrire:

SELECT item.id FROM item 
    INNER JOIN taggeditem ON taggeditem.item_id = item.id 
WHERE 
    taggeditem.tag_id = 1234 
ORDER BY item.rating DESC 

Nous avons des indices (taggeditem.tag_id), (item.id), (item.rating) Le problème avec cette requête est que MySQL ne peut pas utilisez index sur item.rating, car la clé utilisée pour récupérer les lignes n'est pas la même que celle utilisée dans ORDER BY (MySQL: ORDER BY Optimization). Cela conduit à utiliser une table temporaire et filesort, ce qui à son tour conduit à ralentir le temps d'exécution.

La solution que j'ai trouvée est de dénormaliser le champ de tri à la table taggeditem, de sorte que je puisse créer l'index (tag_id, item_rating) sur taggeditem.

J'ai recherché des questions similaires chez SO, et trouvé seulement celui-ci: Mysql slow query: INNER JOIN + ORDER BY causes filesort. La solution était la même.

Donc, je veux demander, est-ce une solution commune à ce problème? Est-ce une bonne pratique de dénormaliser un tas de champs de tri à taggeditem, comme créé, rating? Au SO, vous pouvez trier en utilisant 4 paramètres différents (plus récent, chaud, votes, actif) - cela signifie-t-il qu'ils ont dénormalisé les champs qui sont utilisés pour trier les résultats? Y a-t-il des alternatives à cette solution?

+0

est un article ou un article? confus ... vous pourriez vouloir re-vérifier le SQL – ajreal

+0

J'ai édité le SQL, je voulais dire l'article de la table bien sûr –

Répondre

1

Il existe une alternative standard - modifier les variables système du serveur. Par exemple, vous pouvez tester la valeur sort_buffer_size (2 Mo par défaut). More à ce sujet.

+0

Le problème n'est pas seulement dans le fichier, mais dans la création d'une table temporaire. La plupart du temps, il passe la copie à la table temporaire. Puis-je faire quelque chose avec ça? –

+0

Désolé mais non. C'est la limitation de MySQL. – Lex

0

Dès que vous utilisez un JOIN, et filtrez sur la table jointe, vous êtes coincé avec de mauvaises performances.

Comme vous l'avez dit, la seule façon d'éviter cela est de créer une table dénormalisée.

Pour les sortes de SO, je pense qu'ils ont pas de problème: ils ont juste pour trier les réponses par une colonne de la table des réponses (quelque chose comme SELECT * FROM answers WHERE question_id = 1234 SORT BY answer_date, avec un index sur question_id, answer_date)

Je cherche aussi pour de telles solutions, avec des colonnes à valeurs multiples, et c'est vraiment difficile (les données dénormalisées seraient énormes, car elles doivent traverser toutes les valeurs dans les colonnes à valeurs multiples)

+0

Nous avons un tel problème: lorsque vous filtrez par tag, vous voyez d'abord les questions les plus récentes (ou les plus chaudes, cela n'a pas d'importance). –