Оптимизация MySQL Query с MAX () - PullRequest
       2

Оптимизация MySQL Query с MAX ()

3 голосов
/ 19 декабря 2011

Извиняюсь, если об этом уже спрашивали, но есть ли способ, я могу оптимизировать этот запрос, чтобы он выполнялся быстрее.В настоящее время это занимает около 2 секунд, что, хотя и не так много, это самый медленный запрос на моем сайте, все остальные запросы занимают менее 0,5 с.

Вот мой запрос:

SELECT SQL_CALC_FOUND_ROWS MAX(images.id) AS maxID, celebrity.* FROM images
JOIN celebrity ON images.celeb_id = celebrity.id
GROUP BY images.celeb_id
ORDER BY maxID DESC
LIMIT 0,20

Вот объяснение:

1 SIMPLE celebrity ALL PRIMARY NULL NULL NULL 536 Using temporary; Using filesort
1 SIMPLE images ref celeb_id celeb_id 4 celeborama_ignite.celebrity.id 191

Я в недоумении от того, как улучшить производительность в этом запросе.Я не очень знаком с MySQL, но знаю, что он медленный, потому что я сортирую данные, созданные с помощью MAX (), и у них нет индекса.Я не могу не разобраться с этим, поскольку он дает мне необходимые результаты, но есть ли что-то еще, что я могу сделать, чтобы предотвратить замедление запроса?

Спасибо.

Ответы [ 5 ]

2 голосов
/ 19 декабря 2011

Если вам действительно нужно быстрое решение - тогда не выполняйте такие запросы во время выполнения.

Просто создайте дополнительное поле last_image_id в celebrity таблице и обновите его в случае загрузки нового изображения (с помощьютриггер или логика вашего приложения, не имеет значения)

1 голос
/ 19 декабря 2011

Я бы получил последнее изображение таким образом:

SElECT c.*, i.id AS image_id
FROM celebrity c
JOIN images i ON i.celeb_id = c.id
LEFT OUTER JOIN images i2 ON i2.celeb_id = c.id AND i2.id > i.id
WHERE i2.id IS NULL
ORDER BY image_id DESC
LIMIT 0,20;

Другими словами, попробуйте найти строку i2 для той же знаменитости с более высоким идентификатором, чем i.id.Если внешнему соединению не удается найти это совпадение, то i.id должно быть максимальным идентификатором изображения для данной знаменитости.

SQL_CALC_FOUND_ROWS может привести к тому, что запросы будут выполняться очень медленно.Я обнаружил некоторые случаи, когда простое удаление SQL_CALC_FOUND_ROWS заставляло запрос выполняться в 200 раз быстрее (но в других случаях это также может иметь небольшое значение, это зависит от таблицы, поэтому вам следует протестировать оба способа).

Если вам нужен эквивалент SQL_CALC_FOUND_ROWS, просто запустите отдельный запрос:

SELECT COUNT(*) FROM celebrity;
0 голосов
/ 19 декабря 2011

MYSQL не так хорошо работает с соединениями. Я бы порекомендовал разделить ваш запрос на две части. то есть в первом запросе выберите Celeb, а затем выберите изображение. Просто избегайте объединений. Проверьте эту ссылку - http://phpadvent.org/2011/a-stitch-in-time-saves-nine-by-paul-jones

0 голосов
/ 19 декабря 2011
SELECT STRAIGHT_JOIN *
FROM (
  SELECT MAX(id) as maxID, celeb_id as id
  FROM images
  GROUP BY celeb_id
  ORDER by maxID DESC
  LIMIT 0, 20) as ids
JOIN celebrity USING (id);

в запросе не допускается предварительный расчет номера строки, но дополнительно:

SELECT COUNT(DISTINCT celeb_id)
FROM images;

или даже (если у каждой знаменитости есть изображение):

SELECT COUNT(*) FROM celebrity;

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

0 голосов
/ 19 декабря 2011

Я думаю, вам нужен составной индекс для (celeb_id, id) в таблице images (предположим, что это таблица MyISAM), поэтому GROUP BY celeb_id и MAX(id) могут использовать этот индекс.

Но с большими таблицами вам, вероятно, придется следовать совету @zerkms и добавить новый столбец в таблицу celebrity

...