У меня есть две таблицы, первая таблица содержит все статьи / сообщения в блоге в CMS. Некоторые из этих статей могут также появиться в журнале, и в этом случае они связаны внешним ключом с другой таблицей, которая содержит специфическую для журнала информацию.
Вот упрощенная версия синтаксиса создания таблицы для этих двух таблиц с некоторыми несущественными строками:
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;
CMS содержит около 250 000 статей, и я написал простой скрипт на Python, который можно использовать для заполнения тестовой базы данных образцами данных, если они хотят повторить эту проблему локально.
Если я выберу одну из этих таблиц, у MySQL не будет проблем с выбором подходящего индекса или быстрым поиском статей. Однако, когда две таблицы объединены в один простой запрос, такой как:
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 не может подобрать подходящий запрос и производительность резко падает. Вот соответствующее расширенное объяснение (время выполнения которого больше секунды):
+----+-------------+--------------+--------+-----------------------------------+---------+---------+----------------------------------------+-------+----------+---------------------------------+
| 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 |
+----+-------------+--------------+--------+-----------------------------------+---------+---------+----------------------------------------+-------+----------+---------------------------------+
- РЕДАКТИРОВАТЬ SEPT 30: я могу удалить
WHERE
предложение из этого запроса, но оноEXPLAIN
все равно выглядит так же, и запрос все еще медленный.
Одним из возможных решений является форсирование индекса. Выполнение того же запроса с FORCE INDEX (base_articel_date_published)
результатами приводит к запросу, который выполняется примерно за 1,6 миллисекунды.
+----+-------------+--------------+--------+---------------+-----------------------------+---------+-------------------------+------+-----------+-------------+
| 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 | |
+----+-------------+--------------+--------+---------------+-----------------------------+---------+-------------------------+------+-----------+-------------+
Я бы предпочел не использовать индекс по этому запросу, если я могу избежать его по нескольким причинам. В частности, этот базовый запрос может быть отфильтрован / изменен различными способами (например, фильтрацией по issue_slug
), после чего он base_article_date_published
может перестать быть лучшим индексом для использования.
Кто-нибудь может предложить стратегию повышения производительности для этого запроса?
base_article_is_published
(is_published
) .. мне кажется, это логический тип ..Ответы:
Что об этом, это должно устранить необходимость «Использование временного; Использование файловой сортировки», потому что данные уже в правильной сортировке.
Вам нужно знать хитрость, почему MySQL требует «Использование временного; Использование сортировки файлов», чтобы устранить эту потребность.
Смотрите второй sqlfriddle для объяснения об устранении необходимости
см. http://sqlfiddle.com/#!2/302710/2
Работает довольно хорошо, мне это тоже нужно было некоторое время назад, для таблиц стран / городов см. Демо здесь с примерами данных http://sqlfiddle.com/#!2/b34870/41
Отредактированный вы также можете захотеть проанализировать этот ответ, если base_article.is_published = 1 всегда возвращает 1 запись, как объяснено в вашем объяснении, и таблица доставки INNER JOIN может дать лучшую производительность, как запросы в ответе ниже
/programming/18738483/mysql-slow-query-using-filesort/18774937#18774937
источник
JOIN
только, но MySQL не собирал индекс. Большое спасибо РэймондРЕФАКТОР ЗАПРОСА
или же
ИЗМЕНИТЬ ВАШИ ИНДЕКСЫ
ДАЙТЕ ЭТО ПОПРОБУЙТЕ !!!
источник
LIMIT 30
находится в подзапросе (не все эти 30 строк также будут вmag_articles
таблице). Если я перемещуLIMIT
внешний запрос, производительность будет такой же, как в моем оригинале. Изменить индексы: MySQL также не использует этот индекс. УдалениеWHERE
пункта из моего исходного запроса, кажется, не имеет значения.