2012-01-12 186 views
1

我需要优化这个查询:优化非常缓慢的MySQL查询

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输出:

+----+--------------------+-------+------+-----------------+-------+---------+-----------------------------------------+--------+-------------+ 
| 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 | 
+----+--------------------+-------+------+-----------------+-------+---------+-----------------------------------------+--------+-------------+ 
+1

在问题中添加EXPLAIN计划。你有什么指标在桌子上? – 2012-01-12 14:36:59

+0

我想建议你将查询分成两部分。原因:易于维护,易于缓存,可能执行起来更快 – Anatoly 2012-01-12 14:50:22

+0

表是MyISAM还是InnoDB? – 2012-04-29 15:38:54

回答

2

我认为你可以重写,以避免相关子查询:

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) 

(rut, curso, fetcha)上的索引将适合这个查询。


另一个解决方案是:

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 
     ) 

这将显示不同的结果(在领带的情况下,只有并列排的一个将被显示),但它可能会更快,如果你想限制行数。

+0

Mostrando registros 0 - 29(总共11,874,La consultatardó0.3032 seg)感谢这个查询加速度超过80%我的报告 – mbarrerar 2012-01-12 15:08:37

1
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 
+1

提问者似乎不希望只有一条记录 - 它似乎更像他/她想要给定日期的所有记录。 (“fecha”=西班牙文日期) – Crontab 2012-01-12 14:36:21

+0

嗯......可能是。但是,无论如何,是否有任何理由在子查询中使用'WHERE t.rut = c.rut AND c.curso = t.curso'? – Timur 2012-01-12 14:44:39

+0

是的,我需要所有记录 – mbarrerar 2012-01-12 14:50:53