2012-01-24 5 views
1

Хорошо, так что мои извинения, если этот вопрос слишком прост, но я обычно обрабатываю проблемы программирования, а не проблемы с DBA.SQL Query Optimization

По сути, я пытаюсь ускорить это приложение django (примечание: я не проектировал это ... просто застрял, поддерживая его), а самая большая шея бутылки - это эти запросы, которые генерируются администратором. У нас есть класс контента, 4-5 других подклассы наследуют от и в любое время список мастер залез в админ генерируется запрос, как это:

SELECT `content_content`.`id`, 
     `content_content`.`issue_id`, 
     `content_content`.`slug`, 
     `content_content`.`section_id`, 
     `content_content`.`priority`, 
     `content_content`.`group_id`, 
     `content_content`.`rotatable`, 
     `content_content`.`pub_status`, 
     `content_content`.`created_on`, 
     `content_content`.`modified_on`, 
     `content_content`.`old_pk`, 
     `content_content`.`content_type_id`, 
     `content_image`.`content_ptr_id`, 
     `content_image`.`caption`, 
     `content_image`.`kicker`, 
     `content_image`.`pic`, 
     `content_image`.`crop_x`, 
     `content_image`.`crop_y`, 
     `content_image`.`crop_side`, 
     `content_issue`.`id`, 
     `content_issue`.`special_issue_name`, 
     `content_issue`.`web_publish_date`, 
     `content_issue`.`issue_date`, 
     `content_issue`.`fm_name`, 
     `content_issue`.`arts_name`, 
     `content_issue`.`comments`, 
     `content_section`.`id`, 
     `content_section`.`name`, 
     `content_section`.`audiodizer_id` 
    FROM `content_image` 
INNER 
    JOIN `content_content` 
    ON `content_image`.`content_ptr_id` = `content_content`.`id` 
INNER 
    JOIN `content_issue` 
    ON `content_content`.`issue_id` = `content_issue`.`id` 
INNER 
    JOIN `content_section` 
    ON `content_content`.`section_id` = `content_section`.`id` 
WHERE NOT (`content_content`.`pub_status` = -1) 
ORDER BY `content_issue`.`issue_date` DESC LIMIT 30 

Я побежал EXPLAIN на этом и получил следующее :

+----+-------------+-----------------+--------+-------------------------------------------------------------------------------------------------+---------+---------+--------------------------------------+-------+---------------------------------+ 
| id | select_type | table   | type | possible_keys                     | key  | key_len | ref         | rows | Extra       | 
+----+-------------+-----------------+--------+-------------------------------------------------------------------------------------------------+---------+---------+--------------------------------------+-------+---------------------------------+ 
| 1 | SIMPLE  | content_image | ALL | PRIMARY                       | NULL | NULL | NULL         | 40499 | Using temporary; Using filesort | 
| 1 | SIMPLE  | content_content | eq_ref | PRIMARY,issue_id,content_content_issue_id,content_content_section_id,content_content_pub_status | PRIMARY | 4  | content_image.content_ptr_id   |  1 | Using where      | 
| 1 | SIMPLE  | content_section | eq_ref | PRIMARY                       | PRIMARY | 4  | content_content.section_id   |  1 |         | 
| 1 | SIMPLE  | content_issue | eq_ref | PRIMARY                       | PRIMARY | 4  | content_content.issue_id    |  1 |         | 
+----+-------------+-----------------+--------+-------------------------------------------------------------------------------------------------+---------+---------+--------------------------------------+-------+---------------------------------+ 

Теперь от того, что я прочитал, мне нужно как-то выяснить, как сделать запрос content_image не будет страшно; однако я рисую пробел о том, с чего начать. SQL не совсем моя самая сильная область, поэтому любая помощь будет высоко оценена.

+0

Вы выбираете ** все ** из таблицы 'content_image' (поскольку у вас нет каких-либо' WHERE', отфильтровывающих некоторые строки), поэтому у вас есть fullscan таблицы. Что еще вы ожидаете увидеть? – zerkms

ответ

2

В настоящее время, судя по плану выполнения, MySQL начинается с content_image, извлекая все строк, и только после этого с помощью первичных ключей на других таблицах: content_image имеет внешний ключ к content_content и content_content имеет внешние ключи content_issue и content_section. Кроме того, только после того, как все соединения завершены, он может широко использовать ORDER BY content_issue.issue_date DESC LIMIT 30, поскольку он не может определить, какое из этих объединений может завершиться неудачей, и, следовательно, сколько записей из content_issue действительно понадобится, прежде чем он сможет получить первые тридцать строки вывода.

Итак, я хотел бы попробовать следующее:

  • Изменение JOIN content_issue в JOIN (SELECT * FROM content_issue ORDER BY issue_date DESC LIMIT 30) content_issue. Это позволит MySQL, если он начинается с content_issue и прокладывает себе путь к другим таблицам, чтобы захватить очень небольшое подмножество content_issue.
    • Примечание: это означает, что это изменяет семантику запроса: это означает, что будут извлекаться только записи от максимум 30 content_issue s и, следовательно, если некоторые из этих проблем не имеют опубликованного содержимого с изображениями , то будет извлечено менее 30 записей. У меня недостаточно информации о ваших данных, чтобы оценить, изменит ли это изменение семантики полученные вами результаты.
    • Также обратите внимание: я не предлагаю удалить ORDER BY content_issue.issue_date DESC LIMIT 30 с конца запроса. Я думаю, ты хочешь этого в обоих местах.
  • Добавить индекс на content_issue.issue_date, чтобы оптимизировать вышеуказанный подзапрос.
  • Добавить индекс на content_image.content_ptr_id, поэтому MySQL может работать от content_content до content_image, не выполняя полного сканирования таблицы.
+0

Спасибо за помощь и объяснение! Я сделаю это. – ebensing