Tengo dos tablas, la primera tabla contiene todos los artículos / publicaciones de blog dentro de un CMS. Algunos de estos artículos también pueden aparecer en una revista, en cuyo caso tienen una relación de clave externa con otra tabla que contiene información específica de la revista.
Aquí hay una versión simplificada de la sintaxis de creación de tablas para estas dos tablas con algunas filas no esenciales eliminadas:
CREATE TABLE `base_article` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`date_published` datetime DEFAULT NULL,
`title` varchar(255) NOT NULL,
`description` text,
`content` longtext,
`is_published` int(11) NOT NULL DEFAULT '0',
PRIMARY KEY (`id`),
KEY `base_article_date_published` (`date_published`),
KEY `base_article_is_published` (`is_published`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
CREATE TABLE `mag_article` (
`basearticle_ptr_id` int(11) NOT NULL,
`issue_slug` varchar(8) DEFAULT NULL,
`rubric` varchar(75) DEFAULT NULL,
PRIMARY KEY (`basearticle_ptr_id`),
KEY `mag_article_issue_slug` (`issue_slug`),
CONSTRAINT `basearticle_ptr_id_refs_id` FOREIGN KEY (`basearticle_ptr_id`) REFERENCES `base_article` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
El CMS contiene alrededor de 250,000 artículos en total y he escrito un script simple de Python que se puede usar para llenar una base de datos de prueba con datos de muestra si quieren replicar este problema localmente.
Si selecciono una de estas tablas, MySQL no tiene problemas para elegir un índice apropiado o recuperar artículos rápidamente. Sin embargo, cuando las dos tablas se unen en una consulta simple como:
SELECT * FROM `base_article`
INNER JOIN `mag_article` ON (`mag_article`.`basearticle_ptr_id` = `base_article`.`id`)
WHERE is_published = 1
ORDER BY `base_article`.`date_published` DESC
LIMIT 30
MySQL no puede elegir una consulta adecuada y el rendimiento cae en picado. Aquí está la explicación relevante extendida (el tiempo de ejecución para el cual es más de un segundo):
+----+-------------+--------------+--------+-----------------------------------+---------+---------+----------------------------------------+-------+----------+---------------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+--------------+--------+-----------------------------------+---------+---------+----------------------------------------+-------+----------+---------------------------------+
| 1 | SIMPLE | mag_article | ALL | PRIMARY | NULL | NULL | NULL | 23830 | 100.00 | Using temporary; Using filesort |
| 1 | SIMPLE | base_article | eq_ref | PRIMARY,base_article_is_published | PRIMARY | 4 | my_test.mag_article.basearticle_ptr_id | 1 | 100.00 | Using where |
+----+-------------+--------------+--------+-----------------------------------+---------+---------+----------------------------------------+-------+----------+---------------------------------+
- EDITAR EL 30 DE SEPTIEMBRE: puedo eliminar la
WHERE
cláusula de esta consulta, peroEXPLAIN
todavía se ve igual y la consulta sigue siendo lenta.
Una posible solución es forzar un índice. Ejecutar la misma consulta con FORCE INDEX (base_articel_date_published)
resultados en una consulta que se ejecuta en alrededor de 1.6 milisegundos.
+----+-------------+--------------+--------+---------------+-----------------------------+---------+-------------------------+------+-----------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+--------------+--------+---------------+-----------------------------+---------+-------------------------+------+-----------+-------------+
| 1 | SIMPLE | base_article | index | NULL | base_article_date_published | 9 | NULL | 30 | 833396.69 | Using where |
| 1 | SIMPLE | mag_article | eq_ref | PRIMARY | PRIMARY | 4 | my_test.base_article.id | 1 | 100.00 | |
+----+-------------+--------------+--------+---------------+-----------------------------+---------+-------------------------+------+-----------+-------------+
Preferiría no tener que forzar un índice en esta consulta si puedo evitarlo, por varias razones. En particular, esta consulta básica se puede filtrar / modificar de varias maneras (como el filtrado por el issue_slug
) después de lo cual base_article_date_published
puede que ya no sea el mejor índice para usar.
¿Alguien puede sugerir una estrategia para mejorar el rendimiento de esta consulta?
base_article_is_published
(is_published
) ... me parece que es un tipo booleano ...