J'ai deux tableaux, le premier tableau contient tous les articles / articles de blog dans un CMS. Certains de ces articles peuvent également apparaître dans un magazine, auquel cas ils ont une relation de clé étrangère avec une autre table contenant des informations spécifiques au magazine.
Voici une version simplifiée de la syntaxe de création de table pour ces deux tables avec quelques lignes non essentielles supprimées:
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;
Le CMS contient environ 250 000 articles au total et j'ai écrit un script Python simple qui peut être utilisé pour remplir une base de données de test avec des exemples de données s'ils souhaitent reproduire ce problème localement.
Si je sélectionne dans l'une de ces tables, MySQL n'a aucun problème à choisir un index approprié ou à récupérer des articles rapidement. Cependant, lorsque les deux tables sont réunies dans une requête simple telle que:
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 ne parvient pas à choisir une requête appropriée et les chutes de performances. Voici l'explication pertinente étendue (dont le temps d'exécution est supérieur à une seconde):
+----+-------------+--------------+--------+-----------------------------------+---------+---------+----------------------------------------+-------+----------+---------------------------------+
| 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 |
+----+-------------+--------------+--------+-----------------------------------+---------+---------+----------------------------------------+-------+----------+---------------------------------+
- EDIT SEPT 30: je peux supprimer la
WHERE
clause de cette requête, mais leEXPLAIN
reste toujours le même et la requête est toujours lente.
Une solution potentielle consiste à forcer un index. L'exécution de la même requête avec des FORCE INDEX (base_articel_date_published)
résultats dans une requête qui s'exécute dans environ 1,6 millisecondes.
+----+-------------+--------------+--------+---------------+-----------------------------+---------+-------------------------+------+-----------+-------------+
| 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 | |
+----+-------------+--------------+--------+---------------+-----------------------------+---------+-------------------------+------+-----------+-------------+
Je préférerais ne pas avoir à forcer un index sur cette requête si je peux l'éviter, pour plusieurs raisons. Plus particulièrement, cette requête de base peut être filtrée / modifiée de diverses manières (comme le filtrage par le issue_slug
), après quoi base_article_date_published
il ne peut plus être le meilleur index à utiliser.
Quelqu'un peut-il suggérer une stratégie pour améliorer les performances de cette requête?
base_article_is_published
(is_published
) .. me semble que c'est un type booléen ..