Нужна помощь в оптимизации запроса MySQL с помощью объединений - PullRequest
1 голос
/ 25 марта 2012

У меня все еще есть проблемы с пониманием того, как читать, понимать и оптимизировать объяснения MySQL. Я знаю, чтобы создать индексы для столбцов orderby, но это все. Поэтому я надеюсь, что вы можете помочь мне настроить этот запрос:

EXPLAIN
SELECT specie.id, specie.commonname, specie.block_description, maximage.title,
       maximage.karma, imagefile.file_name, imagefile.width, imagefile.height,
       imagefile.transferred
FROM specie
INNER JOIN specie_map ON specie_map.specie_id = specie.id
INNER JOIN (
    SELECT *
    FROM image
    ORDER BY karma DESC
) AS maximage ON specie_map.image_id = maximage.id
INNER JOIN imagefile ON     imagefile.image_id = maximage.id
                        AND imagefile.type = 'small'
GROUP BY specie.commonname
ORDER BY commonname ASC
LIMIT 0 , 24 

Что этот запрос делает, чтобы найти фотографию с наибольшей кармой для вида. Вы можете увидеть результат этого эфира:

http://www.jungledragon.com/species

У меня есть таблица видов, таблица изображений, таблица сопоставлений между ними и таблица файлов изображений, поскольку для каждого изображения имеется несколько файлов (форматов) изображений.

Объяснить вывод:

enter image description here

Для таблицы specie у меня есть индексы по ее первичному идентификатору и общему имени поля. Что касается таблицы изображений, у меня есть индексы для ее поля id и кармы, а также несколько других, не относящихся к этому вопросу.

Этот запрос в настоящее время занимает от 0,8 до 1,1 с, что, на мой взгляд, слишком медленно. У меня есть подозрение, что правильный индекс ускорит это много раз, но я не знаю, какой именно.

Ответы [ 3 ]

1 голос
/ 25 марта 2012

Настоящая проблема в том, что нет необходимости оптимизировать MySQL объяснение. Обычно существует запрос (или несколько запросов), который вы хотите повысить, и EXPLAIN - это способ узнать, произойдет ли выполнение запроса так, как вы ожидаете.

То есть вам необходимо понять, как должен выглядеть план выполнения и почему, и сравнить его с результатами команды EXPLAIN. Чтобы понять, как план будет выглядеть, вы должны понять как работают индексы в MySQL .

Между тем, ваш запрос сложный, поскольку для эффективного использования индекса он имеет некоторые ограничения: а) одновременное упорядочение по полю из одной таблицы и б) поиск последнего элемента в каждой группе от другого (последнее само по себе является непростой задачей). Поскольку ваша база данных довольно мала, вам повезло, что ваш текущий запрос довольно быстрый (хотя вы считаете его медленным).

Я бы немного переписал запрос (я предполагаю, что для каждого вида есть хотя бы одно фото):

SELECT
   specie.id, specie.commonname, specie.block_description,
   maximage.title, maximage.karma,
   imagefile.file_name, imagefile.width, imagefile.height, imagefile.transferred
FROM (
    SELECT s.id,
           (SELECT i.id
            FROM specie_map sm
            JOIN image i ON sm.image_id = i.id
            WHERE sm.specie_id = s.id
            ORDER BY i.karma DESC
            LIMIT 1) as image_id
    FROM specie s
    ORDER BY s.commonname
    LIMIT 0, 24
) as ids
JOIN specie
  ON ids.id = specie.id
JOIN image as maximage
  ON maximage.id = ids.image_id
JOIN imagefile
  ON imagefile.image_id = ids.image_id AND imagefile.type = 'small';

Вам понадобятся следующие индексы:

  • (commonname) на specie
  • композит (specie_id, image_id) на specie_map
  • композит (id, karma) на image
  • композит (image_id, type) на imagefile

Пейджинг теперь должен происходить внутри подзапроса.

Идея состоит в том, чтобы делать сложные вычисления в подзапросе, который работает только с идентификаторами, и объединять оставшиеся данные сверху. Данные будут упорядочены в порядке результатов подзапроса.

1 голос
/ 26 марта 2012

Я думаю, вы бы пошли отличным путем, избавившись от подзапроса.Посмотрите на первую и последнюю строки результата «объяснения» - он копирует всю таблицу «изображения» во временную таблицу.Вы можете получить тот же результат, заменив подзапрос на INNER JOIN image и переместив ORDER BY karma DESC в окончательное предложение ORDER BY:

SELECT specie.id, specie.commonname, specie.block_description, maximage.title,
       maximage.karma, imagefile.file_name, imagefile.width, imagefile.height,
       imagefile.transferred
FROM specie
INNER JOIN specie_map ON specie_map.specie_id = specie.id
INNER JOIN image AS maximage ON specie_map.image_id = maximage.id
INNER JOIN imagefile ON     imagefile.image_id = maximage.id
                        AND imagefile.type = 'small'
GROUP BY specie.commonname
ORDER BY commonname ASC, karma DESC
LIMIT 0 , 24 
1 голос
/ 25 марта 2012

Было бы лучше, если бы вы могли предоставить структуры таблиц и индексы. Я придумал эту альтернативу, было бы неплохо, если бы вы могли попробовать это и сказать мне, что происходит (мне любопытно!):

SELECT t.*, imf.* FROM (
  SELECT s.*, (SELECT id FROM image WHERE karma = MAX(i.karma) LIMIT 1) AS max_image_id 
  FROM image i 
  INNER JOIN specie_map smap ON smap.image_id = i.id
  INNER JOIN specie s ON s.id = smap.specie_id
  GROUP BY s.commonname 
  ORDER BY s.commonname ASC
  LIMIT 24
) t INNER JOIN imagefile imf
ON t.max_image_id = imf.image_id AND imf.type = 'small' 
...