2009-02-26 3 views
4

Я использую запрос, который обычно выполняется в течение секунды, но иногда занимает от 10 до 40 секунд для завершения. На самом деле я не совсем понимаю, как работает подзапрос, я просто знаю, что он работает, потому что он дает мне 15 строк для каждого файла faverprofileid.Советы по улучшению этого медленного запроса mysql?

Я регистрирую медленные запросы, и это говорит мне, что были проанализированы строки из 5823244, что нечетно, потому что в любой из таблиц нет нигде рядом с множеством строк (таблица фаворитов имеет наибольшее количество в 50 000 строк) ,

Может ли кто-нибудь предложить мне несколько указателей? Это проблема с подзапросом и необходимость использования filesort?

EDIT: Running explain показывает, что таблица пользователей не использует индекс (хотя идентификатор является первичным ключом). В разделе «Дополнительно» сказано: использование временных; Использование filesort.

SELECT F.id,F.created,U.username,U.fullname,U.id,I.* 
FROM favorites AS F 
INNER JOIN users AS U ON F.faver_profile_id = U.id 
INNER JOIN items AS I ON F.notice_id = I.id 
WHERE faver_profile_id IN (360,379,95,315,278,1) 
AND F.removed = 0 
AND I.removed = 0 
AND F.collection_id is null 
AND I.nudity = 0 
AND (SELECT COUNT(*) FROM favorites WHERE faver_profile_id = F.faver_profile_id 
AND created > F.created AND removed = 0 AND collection_id is null) < 15 
ORDER BY F.faver_profile_id, F.created DESC; 
+0

Вы можете получить лучшую синтаксическую раскраску, если вы написали слова «выбрать», «от», «где», «и», «в» и «упорядочить по» маленькими буквами, а также «внутренние», , "on" и "desc" только с первой заглавной буквой. –

+0

Вы пытаетесь выбрать первые 15 элементов для каждого файла faver_profile_id, заказанного созданным? – Quassnoi

+0

Вы запустили ANALYZE на столах? – vladr

ответ

5

Я думаю, что с GROUP BY и HAVING она должна быть быстрее. Это то, что вы хотите?

SELECT F.id,F.created,U.username,U.fullname,U.id, I.field1, I.field2, count(*) as CNT 
FROM favorites AS F 
INNER JOIN users AS U ON F.faver_profile_id = U.id 
INNER JOIN items AS I ON F.notice_id = I.id 
WHERE faver_profile_id IN (360,379,95,315,278,1) 
AND F.removed = 0 
AND I.removed = 0 
AND F.collection_id is null 
AND I.nudity = 0 
GROUP BY F.id,F.created,U.username,U.fullname,U.id,I.field1, I.field2 
HAVING CNT < 15 
ORDER BY F.faver_profile_id, F.created DESC; 

Не знаю, какие поля из items вам нужно, поэтому я поставил заполнителей.

+0

используя группу и имею то, что всплыло у меня в голове, когда я прочитал его проблему ... – GordonB

4

Количество рассмотренных строк представляет собой большое, потому что многие строки были рассмотрены более одного раза. Вы получаете это из-за неверно оптимизированного плана запросов, который приводит к сканированию таблиц при выполнении поиска индекса. В этом случае количество исследованных строк является экспоненциальным, то есть порядка величины, сравнимого с произведением полного числа строк в более чем одной таблице.

  • Убедитесь, что у вас есть запустить ANALYZE TABLE на своих трех таблиц.
  • читать how to avoid table scans, и определить затем создать недостающие индексы
  • Повторить ПРОАНАЛИЗИРУЙТЕ и вновь объяснить ваши запросы
    • число исследованных строк должны резко упасть
    • если нет, то выкладывают полный объяснить план
  • использование query hints принудительное использование индексов (чтобы увидеть имена индексов для таблицы, используйте SHOW INDEX):

SELECT F.id,F.created,U.username,U.fullname,U.id,I.*
FROM favorites AS FFORCE INDEX (faver_profile_id_key)
INNER JOIN users AS UFORCE INDEX FOR JOIN (PRIMARY)ON F.faver_profile_id = U.id
INNER JOIN items AS IFORCE INDEX FOR JOIN (PRIMARY)ON F.notice_id = I.id
WHERE faver_profile_id IN (360,379,95,315,278,1)
AND F.removed = 0
AND I.removed = 0
AND F.collection_id is null
AND I.nudity = 0
AND (SELECT COUNT(*) FROM favoritesFORCE INDEX (faver_profile_id_key)WHERE faver_profile_id = F.faver_profile_id
AND created > F.created AND removed = 0 AND collection_id is null) < 15
ORDER BY F.faver_profile_id, F.created DESC;

Вы также можете изменить свой запрос, чтобы использовать GROUP BY faver_profile_id/HAVING count > 15 вместо вложенного SELECT COUNT(*) подзапроса, как это было предложено vartec , Выполнение как исходного, так и vartec запросов должно быть сопоставимым, если оба они правильно оптимизированы, например. используя подсказки (ваш запрос будет использовать вложенный поиск по индексу, в то время как запрос vartec «s будет использовать хэш на основе стратегии.)

3

Я предлагаю вам использовать Mysql Explain Query, чтобы узнать, как ваш сервер mysql обрабатывает запрос. Моя ставка заключается в том, что ваши индексы не являются оптимальными, но объяснение должно намного лучше, чем моя ставка.

+0

Да, работая объяснение показывает, что таблица пользователей не использует индекс (даже если идентификатор является первичным ключом). В разделе «Дополнительно» сказано: использование временных; Использование filesort. Не уверен, почему он не будет использовать индекс. – makeee

0

Вы можете сделать петлю на каждом ид и использование лимит вместо COUNT (*) подзапроса:

foreach $id in [123,456,789]: 
    SELECT 
    F.id, 
    F.created, 
    U.username, 
    U.fullname, 
    U.id, 
    I.* 
    FROM 
    favorites AS F INNER JOIN 
    users AS U ON F.faver_profile_id = U.id INNER JOIN 
    items AS I ON F.notice_id = I.id 
    WHERE 
    F.faver_profile_id = {$id} AND 
    I.removed = 0 AND 
    I.nudity = 0 AND 
    F.removed = 0 AND 
    F.collection_id is null 
    ORDER BY 
    F.faver_profile_id, 
    F.created DESC 
    LIMIT 
    15; 
0

Я полагаю, результат этого запроса intented будет показан в виде страничного списка. В этом случае, возможно, вы могли бы рассмотреть более простой «несвязанный запрос» и сделать второй запрос для каждой строки, чтобы читать только 15, 20 или 30 элементов. Разве не было тяжелой операции? Это упростило бы запрос, и он не стал бы медленнее при увеличении объединенных таблиц.

Скажите, пожалуйста, если я ошибаюсь.

 Смежные вопросы

  • Нет связанных вопросов^_^