Повышение производительности SQL-запроса с помощью множества левых соединений - PullRequest
3 голосов
/ 24 февраля 2012

У меня есть структура базы данных, обслуживающая новостные статьи со следующими ассоциациями:

  • HABTM news_categories
  • Теги HABTM
  • Загрузка HABTM

Я написал SQL-запрос, чтобы собрать все это воедино:

 SELECT `news_articles`.*, 
 GROUP_CONCAT(DISTINCT tags.title) AS `tags`, 
 GROUP_CONCAT(DISTINCT tags.id) AS `tag_ids`,
 GROUP_CONCAT(DISTINCT news_categories.title) AS `news_categories`,
 GROUP_CONCAT(DISTINCT news_categories.id) AS `news_category_ids`,
 GROUP_CONCAT(DISTINCT news_categories.slug) AS `news_category_slugs`, 
 `news_articles_uploads`.`caption` AS `upload_caption`,
 `uploads`.`title` AS `upload_title`, 
 `uploads`.`basename` AS `upload_basename`,
 `uploads`.`extension` AS `upload_extension`,
 `uploads`.`path` AS `upload_path`
 FROM `news_articles`
 LEFT JOIN `news_articles_tags` ON news_articles_tags.news_article_id = news_articles.id
 LEFT JOIN `tags` ON news_articles_tags.tag_id = tags.id
 LEFT JOIN `news_articles_news_categories` ON news_articles_news_categories.news_article_id = news_articles.id
 LEFT JOIN `news_categories` ON news_articles_news_categories.news_category_id = news_categories.id
 LEFT JOIN `news_articles_uploads` ON (news_articles_uploads.news_article_id = news_articles.id AND news_articles_uploads.order = 0)
 LEFT JOIN `uploads` ON news_articles_uploads.upload_id = uploads.id 
 WHERE (news_categories.slug IN ("category-one","category-two","category-three","category-four","category-five")) AND (news_articles.published = 1)
 GROUP BY `news_articles`.`id`
 ORDER BY `news_articles`.`lead_article` DESC, `news_articles`.`created` DESC LIMIT 20;

Проблема в том, что во время выполнения запроса он медленный, и в периоды занятости загрузка ЦП выходит из-под контроля.!

Вот ОБЪЯСНЕНИЕ для вышеуказанного запроса (щелкните правой кнопкой мыши на открывшейся вкладке, чтобы увидеть полный размер):

Explain result for the above query

Схему можно найти здесь: http://pastie.org/private/qoe2qo16rbqr5mptb4bug

На сервере работает MySQL 5.1.55, а веб-сайт использует Zend Framework для выполнения запроса и PHP 5.2.8.

Я прошел через журнал медленных запросов MySQLи добавил недостающие индексы, насколько мне известно, но запрос все еще обнаруживается как выполнение 1-3 секунд для выполнения.Если у кого-то есть идеи, я буду очень благодарен.Заранее спасибо.

Ответы [ 2 ]

3 голосов
/ 24 февраля 2012

Поскольку в предложении "WHERE" изначально содержалось "AND" для категорий новостей в указанном списке, это заставляло бы объединяться, чтобы попасть туда, как INNER, а не LEFT JOIN.Кроме того, я бы попытался добавить предложение "STRAIGHT_JOIN".Как правило, это заставляет движок выполнять объединение в указанном порядке, вместо того, чтобы пытаться придумать для вас собственную альтернативу ... особенно, когда другие таблицы являются более "справочными" ссылками.применить индекс, как предложено Иорданией.

SELECT STRAIGHT_JOIN
      NA.*, 
      GROUP_CONCAT(DISTINCT tags.title) AS `tags`, 
      GROUP_CONCAT(DISTINCT tags.id) AS tag_ids,
      GROUP_CONCAT(DISTINCT NC.title) AS news_categories,
      GROUP_CONCAT(DISTINCT NC.id) AS news_category_ids,
      GROUP_CONCAT(DISTINCT NC.slug) AS news_category_slugs, 
      NAUp.`caption` AS upload_caption,
      Up1.`title` AS upload_title, 
      Up1.`basename` AS upload_basename,
      Up1.`extension` AS upload_extension,
      Up1.`path` AS upload_path
   FROM 
      news_articles NA
         INNER JOIN news_articles_news_categories NACats
            ON NA.id = NACats.news_article_id

            INNER JOIN news_categories NC
               ON NACats.news_category_id = NC.id
               AND NC.slug IN ( "category-one",
                                "category-two",
                                "category-three",
                                "category-four",
                                "category-five" )


         LEFT JOIN news_articles_tags NATags
            ON NA.ID = NATags.news_article_id

            LEFT JOIN tags
               ON NATags.tag_id = tags.id

         LEFT JOIN news_articles_uploads NAUp
            ON    NA.ID = NAUp.news_article_id 
              AND NAUp.order = 0

            LEFT JOIN uploads Up1
               ON NAUp.upload_id = Up1.id 

   WHERE 
      NA.Published = 1
   GROUP BY 
      NA.ID
   ORDER BY 
      NA.lead_article DESC, 
      NA.created DESC 
   LIMIT 20;
3 голосов
/ 24 февраля 2012

Есть ли у вас индекс news_articles. lead_article, news_articles. created, индекс, содержащий оба столбца.

create index news_articles_x1 on news_articles (lead_articles, created);

Без него вы не будете братьПреимущество предложения order by limit позволяет сканировать и сортировать всю таблицу.

Также я хотел бы задать вопрос, нужны ли вам все эти данные за один раз?

...