Search code examples
mysqlinnodbindexingexplain

Optimize Query creating indexes to remove using temporary and using filesort from query plan


I have this query that I've optimized to be run in half the time it was in the beginning.

Now I want to improve it's execution creating some indexes, but haven't found the way to do it.

The query is:

SELECT straight_join CONCAT(IFNULL(u.nombre,''), ' ', IFNULL(u.apellidos,''), ' ', IFNULL(u.apellido2,''), ' ; ', IFNULL(u.correo,''), ' ; ', IFNULL(u.telefono,''), ' ', 
                            IFNULL(u.horario,''), ' ; ', IFNULL(u.telefono2,''), ' ', IFNULL(u.horario2,''), ' ; ', IFNULL(u.fecha_prox_llamada,'')) AS datos, 
        usuariohist1.web, usuariohist1.comentario, u.usuario_id, estad.estad_id, 
        estad.fecha, estad.tipoinf, estad.web_id, estad.procede, estad.convocatoria_id, eventos.evento as curso, 
        centros.centro, centros.centro_id 
    FROM centros 
    INNER JOIN convocatorias ON centros.centro_id = convocatorias.centro_id  
    INNER JOIN eventos ON eventos.evento_id = convocatorias.evento_id 
    INNER JOIN estad ON estad.convocatoria_id = convocatorias.convocatoria_id 
    INNER JOIN usuarios AS u ON estad.usuario_id = u.usuario_id 
    LEFT JOIN (select web, comentario, usuario_id FROM usuariohist order by fecha desc, id desc ) as usuariohist1       
        ON u.usuario_id = usuariohist1.usuario_id OR u.n_usuario = usuariohist1.usuario_id 
WHERE centros.segcupones = 1 and u.fecha_prox_llamada = '2013-02-13' 
    group by u.usuario_id, estad.web_id, estad.convocatoria_id 
    order by estad.fecha desc \G    

The execution plan is:

*************************** 1. row ***************************
           id: 1
  select_type: PRIMARY
        table: centros
         type: ALL
possible_keys: PRIMARY,centro_id,centro_id_2
          key: NULL
      key_len: NULL
          ref: NULL
         rows: 2622
        Extra: Using where; Using temporary; Using filesort
*************************** 2. row ***************************
           id: 1
  select_type: PRIMARY
        table: convocatorias
         type: ref
possible_keys: PRIMARY,FK_convocatorias_evento_id,FK_convocatorias_centro_id
          key: FK_convocatorias_centro_id
      key_len: 3
          ref: formaweb_op.centros.centro_id
         rows: 66
        Extra: Using where
*************************** 3. row ***************************
           id: 1
  select_type: PRIMARY
        table: eventos
         type: eq_ref
possible_keys: PRIMARY
          key: PRIMARY
      key_len: 4
          ref: formaweb_op.convocatorias.evento_id
         rows: 1
        Extra: 
*************************** 4. row ***************************
           id: 1
  select_type: PRIMARY
        table: estad
         type: ref
possible_keys: FK_Estad_Convocatorias,FK_Estad_Usuarios
          key: FK_Estad_Convocatorias
      key_len: 4
          ref: formaweb_op.convocatorias.convocatoria_id
         rows: 4
        Extra: 
*************************** 5. row ***************************
           id: 1
  select_type: PRIMARY
        table: u
         type: eq_ref
possible_keys: PRIMARY,usuario_id
          key: PRIMARY
      key_len: 4
          ref: formaweb_op.estad.usuario_id
         rows: 1
        Extra: Using where
*************************** 6. row ***************************
           id: 1
  select_type: PRIMARY
        table: <derived2>
         type: ALL
possible_keys: NULL
          key: NULL
      key_len: NULL
          ref: NULL
         rows: 23971
        Extra: 
*************************** 7. row ***************************
           id: 2
  select_type: DERIVED
        table: usuariohist
         type: ALL
possible_keys: NULL
          key: NULL
      key_len: NULL
          ref: NULL
         rows: 28594
        Extra: Using filesort
7 rows in set (0.48 sec)

I've created a covering index on centros table (centro_id, centro, segcupones), but performance has not improved (or very little). Now execution plan shows using index but also using temporary and filesort.

*************************** 1. row ***************************
           id: 1
  select_type: PRIMARY
        table: centros
         type: index
possible_keys: PRIMARY,centro_id,centro_id_2,centro_id_3
          key: centro_id_3
      key_len: 307
          ref: NULL
         rows: 2873
        Extra: Using where; Using index; Using temporary; Using filesort
*************************** 2. row ***************************
           id: 1
  select_type: PRIMARY
        table: convocatorias
         type: ref
possible_keys: PRIMARY,FK_convocatorias_evento_id,FK_convocatorias_centro_id
          key: FK_convocatorias_centro_id
      key_len: 3
          ref: formaweb_op.centros.centro_id
         rows: 66
        Extra: Using where
*************************** 3. row ***************************
           id: 1
  select_type: PRIMARY
        table: eventos
         type: eq_ref
possible_keys: PRIMARY
          key: PRIMARY
      key_len: 4
          ref: formaweb_op.convocatorias.evento_id
         rows: 1
        Extra: 
*************************** 4. row ***************************
           id: 1
  select_type: PRIMARY
        table: estad
         type: ref
possible_keys: FK_Estad_Convocatorias,FK_Estad_Usuarios
          key: FK_Estad_Convocatorias
      key_len: 4
          ref: formaweb_op.convocatorias.convocatoria_id
         rows: 4
        Extra: 
*************************** 5. row ***************************
           id: 1
  select_type: PRIMARY
        table: u
         type: eq_ref
possible_keys: PRIMARY,usuario_id
          key: PRIMARY
      key_len: 4
          ref: formaweb_op.estad.usuario_id
         rows: 1
        Extra: Using where
*************************** 6. row ***************************
           id: 1
  select_type: PRIMARY
        table: <derived2>
         type: ALL
possible_keys: NULL
          key: NULL
      key_len: NULL
          ref: NULL
         rows: 23971
        Extra: 
*************************** 7. row ***************************
           id: 2
  select_type: DERIVED
        table: usuariohist
         type: ALL
possible_keys: NULL
          key: NULL
      key_len: NULL
          ref: NULL
         rows: 28594
        Extra: Using filesort
7 rows in set (0.54 sec)

I've also created index for table usuariohist (DERIVED) but no success, the query plan still the same. I've tried these indexes: (fecha, id), (usuario_id, fecha, id) and a covering index (usuario_id, fecha, id, web, comentario).

Index from tables involved:

CREATE TABLE `centros` (

    ...FIELDS...

  PRIMARY KEY (`centro_id`),
  KEY `FK_Centros_Aux_Paises` (`pais_id`),
  KEY `FK_Centros_Aux_Provincias` (`provincia_id`),
  KEY `FK_Centros_Centros_Grupo` (`grupo_id`),
  KEY `centro_id_2` (`centro_id`,`tipouniversidad`),
  KEY `centro_id` (`centro_id`,`padre_id`,`provincia_id`),
  KEY `centro_id_3` (`centro_id`,`centro`,`segcupones`),
  CONSTRAINT `FK_Centros_Aux_Paises` FOREIGN KEY (`pais_id`) REFERENCES `aux_paises` (`pais_id`) ON DELETE NO ACTION ON UPDATE NO ACTION,
  CONSTRAINT `FK_Centros_Aux_Provincias` FOREIGN KEY (`provincia_id`) REFERENCES `aux_provincias` (`provincia_id`) ON DELETE NO ACTION ON UPDATE NO ACTION,
  CONSTRAINT `FK_Centros_Centros_Grupo` FOREIGN KEY (`grupo_id`) REFERENCES `centros_grupo` (`grupo_id`) ON DELETE NO ACTION ON UPDATE NO ACTION
) ENGINE=InnoDB AUTO_INCREMENT=3373 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci


CREATE TABLE `convocatorias` (

    ...FIELDS...

  PRIMARY KEY (`convocatoria_id`),
  KEY `FK_Convocatorias_Centros` (`centro_id`),
  KEY `FK_Convocatorias_Eventos` (`evento_id`),
  CONSTRAINT `FK_Convocatorias_Centros` FOREIGN KEY (`centro_id`) REFERENCES `centros` (`centro_id`) ON DELETE NO ACTION ON UPDATE NO ACTION,
  CONSTRAINT `FK_Convocatorias_Eventos` FOREIGN KEY (`evento_id`) REFERENCES `eventos` (`evento_id`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci 


CREATE TABLE `eventos` (

    ...FIELDS...

  PRIMARY KEY (`evento_id`),
  KEY `evento` (`evento`,`temario`(255))
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci



CREATE TABLE `estad` (

    ...FIELDS...

  CONSTRAINT `FK_Estad_Convocatorias` FOREIGN KEY (`convocatoria_id`) REFERENCES `convocatorias` (`convocatoria_id`) ON DELETE NO ACTION ON UPDATE NO ACTION,
  CONSTRAINT `FK_Estad_Usuarios` FOREIGN KEY (`usuario_id`) REFERENCES `usuarios` (`usuario_id`) ON DELETE NO ACTION ON UPDATE NO ACTION
) ENGINE=InnoDB AUTO_INCREMENT=360851 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci



CREATE TABLE `usuarios` (

    ...FIELDS...

  PRIMARY KEY (`usuario_id`),
  KEY `FK_Usuarios_WEBS` (`web_id`),
  KEY `usuario` (`usuario`,`clave`),
  KEY `usuario_id` (`usuario_id`,`web_id`),
  CONSTRAINT `FK_usuarios_web_id` FOREIGN KEY (`web_id`) REFERENCES `webs` (`web_id`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB AUTO_INCREMENT=256323 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci


CREATE TABLE `usuariohist` (

    ...FIELDS...

  PRIMARY KEY (`id`),
  KEY `usuario_id` (`usuario_id`,`fecha`,`id`),
  KEY `usuario_id_2` (`usuario_id`,`fecha`,`id`,`web`,`comentario`(255))
) ENGINE=InnoDB AUTO_INCREMENT=28153 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci

Anyone knows how I can optimize this query creating indexes, please explain the solution.

Thanks in advance!


Solution

  • Just a couple of pointers - I don't have time right now for a full analysis:

    For any query to reach it's maximum potential, if there are explicit values provided, it helps enormously if they drive the query.
    Your query has specific values for centros.segcupones and u.fecha_prox_llamada but there is no index on the last one, and a only joint index on the first one, so your first port of call is to create an index for u.fecha_prox_llamada, then maybe see how an single index on centros.segcupones goes.