Eu tenho duas tabelas, a primeira tabela contém todos os artigos / postagens de blog em um CMS. Alguns desses artigos também podem aparecer em uma revista; nesse caso, eles têm um relacionamento de chave estrangeira com outra tabela que contém informações específicas da revista.
Aqui está uma versão simplificada da sintaxe de criação de tabela para essas duas tabelas com algumas linhas não essenciais removidas:
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;
O CMS contém cerca de 250.000 artigos no total e eu escrevi um script Python simples que pode ser usado para preencher um banco de dados de teste com dados de amostra, se eles quiserem replicar esse problema localmente.
Se eu selecionar uma dessas tabelas, o MySQL não terá problemas para escolher um índice apropriado ou recuperar artigos rapidamente. No entanto, quando as duas tabelas são unidas em uma consulta simples, 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
O MySQL falha ao escolher uma consulta e desempenho apropriados. Aqui está a explicação relevante estendida (cujo tempo de execução é superior a um 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 SETEMBRO 30: Posso remover a
WHERE
cláusula desta consulta, mas aEXPLAIN
aparência ainda é a mesma e a consulta ainda é lenta.
Uma solução potencial é forçar um índice. A execução da mesma consulta com FORCE INDEX (base_articel_date_published)
resultados em uma consulta que é executada em cerca de 1,6 milissegundos.
+----+-------------+--------------+--------+---------------+-----------------------------+---------+-------------------------+------+-----------+-------------+
| 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 | |
+----+-------------+--------------+--------+---------------+-----------------------------+---------+-------------------------+------+-----------+-------------+
Eu preferiria não precisar forçar um índice nessa consulta, se eu puder evitá-la, por vários motivos. O mais notável é que essa consulta básica pode ser filtrada / modificada de várias maneiras (como a filtragem por issue_slug
), após as quais base_article_date_published
pode não ser mais o melhor índice a ser usado.
Alguém pode sugerir uma estratégia para melhorar o desempenho desta consulta?
base_article_is_published
(is_published
) .. olha para mim, é um tipo de boolean ..