Optimize very slow Mysql Query

119 views Asked by At

I need help optimizing this query:

SELECT 
    c.rut, c.nombre, c.apellido, c.estado, c.porcentajeavance,  
    c.porcentajenota, c.nota, c.curso, c.fecha_inicio,   
    c.fecha_termino, c.grupo, c.fecha, c.cargo
FROM tbl_historico c
WHERE fecha = ( 
    SELECT max( t.fecha ) fecha
    FROM tbl_historico t
    WHERE t.rut = c.rut AND c.curso = t.curso 
)

EXPLAIN output:

+----+--------------------+-------+------+-----------------+-------+---------+-----------------------------------------+--------+-------------+
| id | select_type        | table | type | possible_keys   | key   | key_len | ref                                     | rows   | Extra       |
+----+--------------------+-------+------+-----------------+-------+---------+-----------------------------------------+--------+-------------+
|  1 | PRIMARY            | c     | ALL  | NULL            | NULL  | NULL    | NULL                                    | 158008 | Using where |
|  2 | DEPENDENT SUBQUERY | t     | ref  | rut,rut_2,rut_3 | rut_3 | 514     | campus_mdle1.c.rut,campus_mdle1.c.curso |     27 | Using index |
+----+--------------------+-------+------+-----------------+-------+---------+-----------------------------------------+--------+-------------+
2

There are 2 answers

1
ypercubeᵀᴹ On BEST ANSWER

I think you can rewrite it to avoid the correlated subquery:

SELECT c.rut, c.nombre, c.apellido, c.estado, c.porcentajeavance
     , c.porcentajenota, c.nota, c.curso, c.fecha_inicio
     , c.fecha_termino, c.grupo, c.fecha, c.cargo
FROM 
      tbl_historico AS c
  JOIN
      ( SELECT rut, curso, MAX(fetcha) AS fetcha
        FROM tbl_historico 
        GROUP BY rut, curso 
      ) AS grp
    ON (grp.rut, grp.curso, grp.fetcha)
     = ( c.rut,   c.curso,   c.fetcha)

An index on (rut, curso, fetcha) would be good for this query.


Another solution would be:

SELECT c.rut, c.nombre, c.apellido, c.estado, c.porcentajeavance
     , c.porcentajenota, c.nota, c.curso, c.fecha_inicio
     , c.fecha_termino, c.grupo, c.fecha, c.cargo
FROM 
      ( SELECT rut, curso
        FROM tbl_historico
        GROUP BY rut, curso
        ORDER BY rut, curso                --- custom order and
        LIMIT 30 OFFSET 0                  --- limit here
      ) AS dc
  JOIN
      tbl_historico AS c
    ON c.PK =                              --- the Primary Key of the table here
       ( SELECT h.PK                       --- and here
         FROM tbl_historico AS h
         WHERE (h.rut, h.curso) = (dc.rut, dc.curso)
         ORDER BY h.fetcha DESC
         LIMIT 1  
       ) 

This will show different result (in case of ties, only one of the tied rows will be shown) but it could be even faster if you want to limit the number of rows.

2
Timur On
SELECT c.rut, c.nombre, c.apellido,c.estado, c.porcentajeavance,  
       c.porcentajenota, c.nota, c.curso, c.fecha_inicio, c.fecha_termino,c.grupo,c.fecha,c.cargo
FROM tbl_historico c
ORDER BY c.fecha DESC
LIMIT 1