【问题标题】:Optimize very slow Mysql Query优化非常慢的Mysql Query
【发布时间】:2012-02-08 20:09:21
【问题描述】:

我需要帮助优化此查询:

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 
)

解释输出:

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

【问题讨论】:

  • 在问题中添加 EXPLAIN 计划。你有什么索引?
  • 我建议您将查询一分为二。原因:易于维护、易于缓存并且执行速度可能更快
  • 表是 MyISAM 还是 InnoDB ?

标签: mysql sql subquery query-tuning


【解决方案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 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  
       ) 

这将显示不同的结果(如果出现平局,只会显示平局之一),但如果您想限制行数,它可能会更快。

【讨论】:

  • 相当不错的 Mostrando registros 0 - 29(总共 11,874 个,La Consulta tardó 0.3032 seg)感谢这个查询加速了我的报告的 80%
【解决方案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 c
ORDER BY c.fecha DESC
LIMIT 1

【讨论】:

  • 提问者似乎不想要一个记录 - 似乎他/她想要给定日期的所有记录。 (“fecha”=西班牙语的日期)
  • 嗯...可能是。但是,无论如何,有什么理由在子查询中使用WHERE t.rut = c.rut AND c.curso = t.curso
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-07-04
  • 2013-07-31
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-02-27
相关资源
最近更新 更多