2009-09-24 9 views
1

J'ai une table Cars avec datetime (DATE) et bit (PUBLIC).Utilisation de filesort pour trier par colonne datetime dans MySQL

Maintenant, je voudrais prendre les lignes commandées par DATE et PUBLIC = 1 donc j'utiliser:

select 
    c.* 
from 
    Cars c 
WHERE 
    c.PUBLIC = 1 
ORDER BY 
    DATE DESC 

Mais malheureusement, quand j'utilise expliquer pour voir ce qui se passe j'ai ceci:

1 SIMPLE a ALL  IDX_PUBLIC,DATE  NULL NULL NULL 103  Using where; Using filesort 

Et il prend 0,3 ms pour prendre ces données alors que j'ai seulement 100 lignes. Y at-il un autre moyen de désactiver le fichier?

Si je vais aux index j'ai l'index sur (PUBLIC, DATE) pas unique.

Tableau def:

CREATE TABLE IF NOT EXISTS `Cars` (
    `ID` int(11) NOT NULL auto_increment, 
    `DATE` datetime NOT NULL, 
    `PUBLIC` binary(1) NOT NULL default '0' 
    PRIMARY KEY (`ID`), 
    KEY `IDX_PUBLIC` (`PUBLIC`), 
    KEY `DATE` (`PUBLIC`,`DATE`) 
) ENGINE=MyISAM AUTO_INCREMENT=186 ; 
+0

Pourriez-vous s'il vous plaît poster la définition de votre table? Il suffit de lancer 'SHOW CREATE TABLE Cars' – Quassnoi

+0

@Quassnoi - Ok. J'ai ajouté –

+0

300 microsecondes pour 100 lignes? 3 microsecondes par rangée? Cette performance n'est pas pourrie. –

Répondre

1

Vous devez avoir un indice composite sur (public, date)

De cette façon, MySQL filtrera sur public et trier sur date.

De votre EXPLAIN je vois que vous n'avez pas un index composite sur (public, date). Vous avez à la place deux index différents sur public et sur date. Au moins, c'est ce que disent leurs noms IDX_PUBLIC et DATE.

Mise à jour:

Vous colonne public n'est pas un BIT, c'est un BINARY(1). C'est un type de caractère et utilise la comparaison de caractères.

Lors de la comparaison d'entiers à des caractères, MySQL convertit ce dernier en premier, et non l'inverse.

Ces requêtes renvoient des résultats différents:

CREATE TABLE t_binary (val BINARY(2) NOT NULL); 

INSERT 
INTO t_binary 
VALUES 
(1), 
(2), 
(3), 
(10); 

SELECT * 
FROM t_binary 
WHERE val <= 10; 

--- 
1 
2 
3 
10 

SELECT * 
FROM t_binary 
WHERE val <= '10'; 
--- 
1 
10 

Modifiez votre public colonne à une bit ou de réécrire votre requête comme cela:

SELECT c.* 
FROM Cars c 
WHERE c.PUBLIC = '1' 
ORDER BY 
     DATE DESC 

, i. e. comparez des caractères avec des caractères, pas des entiers.

+0

J'ai un index sur (PUBLIC) et le second est composite (PUBLIC, DATE). Devrais-je retirer le premier? –

+0

Le deuxième devrait être utilisé quand même. Pourriez-vous s'il vous plaît poster la définition de la table? – Quassnoi

+0

Pas de problème. J'ai ajouté l'onglet def –

1

Si vous commandez par date, une sorte sera nécessaire. S'il n'y a pas d'index par date, un fichier sera utilisé. La seule façon de se débarrasser de cela serait d'ajouter un index à la date ou ne pas faire l'ordre par.

En outre, un fichier ne signifie pas toujours que le fichier sera trié sur le disque. Il pourrait être en train de le trier en mémoire si la table est suffisamment petite ou si le tampon de tri est assez grand. Cela signifie simplement que la table elle-même doit être triée.

On dirait que vous avez déjà un index à date, et puisque vous utilisez PUBLIC dans votre clause where, MySQL devrait pouvoir utiliser cet index. Cependant, l'optimiseur a peut-être décidé que puisque vous avez si peu de lignes, cela ne vaut pas la peine de vous soucier de l'index. Essayez d'ajouter 10 000 lignes environ à la table, ré-analysez-la et voyez si cela change le plan.

Questions connexes