2009-12-09 5 views
2

J'ai une requête dans laquelle je commande un tableau de classement par un certain nombre de champs pour gérer la situation que certains champs dans le résultat peuvent avoir la même valeur. Je suis curieux de savoir pourquoi lorsque les champs suivants ne sont pas requis pour la commande secondaire, la requête est toujours plus lente.mySQL ORDER optimisation

Un exemple est un tableau des articles qui sont votés. Il contans un champ total qui est une valeur mise en cache de votes_up moins votes_down. Lors de l'interrogation d'un leaderboard (disons top 10) si deux totaux sont égaux, il passe ensuite au votes_up. Et enfin, si les deux sont égaux, un autre champ pourrait être utilisé comme la clé primaire.

Voici un exemple de table:

CREATE TABLE `items` (
    `id` int unsigned NOT NULL, 
    `votes_up` mediumint NOT NULL, 
    `votes_down` mediumint NOT NULL, 
    `total` mediumint NOT NULL, 
    PRIMARY KEY (`id`), 
    KEY `votes_up` (`votes_up`), 
    KEY `total` (`total`) 
) 

Une requête top-ten de base avec la commande sur un champ est rapide comme l'éclair; par exemple:

SELECT * FROM `items` ORDER BY `total` DESC LIMIT 10; 
(0.00 secs) 

L'ajout du champ votes_up pour la commande secondaire le ralentit considérablement; par exemple:

SELECT * FROM `items` ORDER BY `total` DESC, `votes_up` DESC LIMIT 10; 
(0.15 secs) 

Ajout d'un troisième, même la clé primaire le ralentit davantage; .: par exemple

SELECT * FROM `items` ORDER BY `total` DESC, `votes_up` DESC, `id` DESC LIMIT 10; 
(0.18 secs) 

Est-il possible d'optimiser cette requête de sorte que lorsque les valeurs de champ total sont toutes uniques que les clauses de commande secondaires sont ignorées et n'encourent pas de frais généraux?

Répondre

5

Un index multi-colonnes peut accélérer ce processus. Vous pouvez créer un index sur 'total' et 'votes_up'. L'ajout du 'id' ne fera rien puisque ce sera toujours unique.

Avec un index multi-colonnes, conservez-les toujours dans le même ordre que celui utilisé pour votre commande.

+0

Fabuleux. cela a fonctionné un régal. Sauf que j'ai dû ajouter la clé primaire aussi. sans le 'id 'dans la clé seulement l'ordre sur les deux premiers champs a été amélioré, en ajoutant le troisième était de retour à la requête plus lente. avec trois il est l'éclair: ALTER TABLE '' INDEX ADD points'une leaderboard' ('total',' votes_up', 'id') Merci! –

+0

Ah, super! Je me demandais pourquoi vous aviez l'ID dans le troisième sélectionner, car ce sera toujours unique (comme la clé primaire). On dirait que ce sera identique à la 2ème requête. – jonstjohn

0

Vous pouvez sélectionner vos résultats dans une table temporaire et, à partir de là, déterminer l'unicité de la colonne 'total' et gérer toute subordination en conséquence. Alternativement, vous pouvez mettre votre requête principale (ordre par 'total') dans une vue, et seulement appliquer la commande secondaire sur cela; cela devrait l'accélérer quelque peu.

+0

merci, bien que les 10 premières lignes ne soient pas les bonnes, donc les commander serait inutile. c'est-à-dire que le vrai # 10 pourrait être à # 12 et donc pas dans l'ensemble initial –

+0

Eh bien, je ne m'attendais pas particulièrement à ce que la limite soit dans la vue, mais oui, je vois ce que vous voulez dire. Dans tous les cas, l'autre réponse de l'index multi-colonne est clairement la voie à suivre ... –