La base de datos es MySQL con el motor MyISAM.GRUPO POR optimización de consultas
definición de tabla:
CREATE TABLE IF NOT EXISTS matches (
id int(11) NOT NULL AUTO_INCREMENT,
game int(11) NOT NULL,
user int(11) NOT NULL,
opponent int(11) NOT NULL,
tournament int(11) NOT NULL,
score int(11) NOT NULL,
finish tinyint(4) NOT NULL,
PRIMARY KEY (id),
KEY game (game),
KEY user (user),
KEY i_gfu (game , finish , user)
) ENGINE=MyISAM DEFAULT CHARSET=latin1 AUTO_INCREMENT=3149047 ;
he puesto un índice en (game, finish, user)
pero esta consulta GROUP BY
todavía necesita 0,4 - 0,6 segundos para ejecutar:
SELECT user AS player
, COUNT(id) AS times
FROM matches
WHERE finish = 1
AND game = 19
GROUP BY user
ORDER BY times DESC
La salida EXPLAIN
:
| id | select_type | table | type | possible_keys | key | key_len |
| 1 | SIMPLE | matches | ref | game,i_gfu | i_gfu | 5 |
| ref | rows | Extra |
| const,const | 155855 | Using where; Using temporary; Using filesort |
¿Hay alguna manera de hacerlo más rápido? La tabla tiene aproximadamente 800,000 registros.
EDIT: I cambió COUNT(id)
en COUNT(*)
y el tiempo se redujo a 0,08 - 0,12 segundos. Creo que lo he intentado antes de hacer el índice y olvidé cambiarlo de nuevo después.
En la salida explicar la mediante el índice de explica la aceleración:
| rows | Extra |
| 168029 | Using where; Using index; Using temporary; Using filesort |
(pregunta al margen:? Es esta caída de un factor de 5 normal)
hay cerca de 2.000 usuarios, así que la clasificación final, incluso si usa filesort, no perjudica el rendimiento. Intenté sin ORDER BY
y todavía toma casi el mismo tiempo.
La razón por la que el recuento (\ *) tiene un rendimiento mucho más rápido que count (id) es que MySQL tiene una optimización específica para el caso de conteo (\ *). El caso de conteo (id) hace una segunda pasada a través de los datos para recuperar los resultados, donde el recuento (\ *) usa los contadores de fila internos existentes. Use conteo (\ *) siempre que sea posible. –