Как оптимизировать запрос, содержащий два идентичных подзапроса, кроме агрегатной функции?

#mysql #sql

#mysql #sql

Вопрос:

Я пытаюсь написать простой запрос, который генерирует список книг, ранжированных по двум параметрам: самый последний обзор и общее количество обзоров. Чтобы вычислить самую последнюю дату рецензирования для каждой книги, я использую подзапрос и минимальную агрегатную функцию. Чтобы вычислить общее количество отзывов для каждой книги, я использую точно такой же подзапрос, но вместо него использую агрегатную функцию COUNT .

Это кажется неэффективным. Есть ли способ объединить эти подзапросы в один вызов и при этом иметь доступ к обоим агрегированным значениям в предложениях HAVING и ORDER BY запроса?

Вот псевдозапрос:

 SELECT DISTINCT
    (SELECT MIN(review.pub_date)
        FROM review
        WHERE book.id = review.book_id
        AND ...
        AND ...
        AND ...
    ) AS most_recent_date,
    (SELECT COUNT(review.pub_date)
        FROM review
        WHERE book.id = review.book_id
        AND ...
        AND ...
        AND ...
    ) AS review_count,
    book.id, book.pub_date, book.title, book.author
FROM book
INNER JOIN review
    ON (review.book_id = book.id)
WHERE (
    ...
)
HAVING (most_recent_date > '$DATE')
ORDER BY review_count DESC
  

Я попытался объединить их в один и переместить агрегатные функции из подзапроса в предложения HAVING и ORDER BY, но я не смог получить никаких результатов таким образом.

Заранее спасибо.

Комментарии:

1. Это не имеет смысла использовать having , если у вас нет group by предложения

2. @barranka . , , Это разумный синтаксис в MySQL. Это расширение, которое позволяет использовать псевдонимы столбцов в условии.

3. @GordonLinoff этого не знал! Спасибо!

Ответ №1:

Я не думаю, что вам нужны подзапросы для этого:

 select 
    book.id, book.pub_date, book.title, book.author, 
    min(review.pub_date) as most_recent_date, -- are you sure you want "min"? ("max" makes more sense to me) 
    count(review.pub_date) as review_count
from book
    left join review on book.id = review.book_id
where ... -- Define here any conditions, including those inside the subquery
group by book.id
having most_recent_date > ?
order by review_count desc
  

Другой способ оптимизировать это — создать временные таблицы с желаемыми результатами, а затем перенести результаты в ваш запрос.

Комментарии:

1. Большое спасибо. Это сократило время моего запроса на 90%!

2. @HakanB. Всегда делайте это просто … обычно это лучший способ сделать что-то 😉

3. 1 . . . Но в качестве примечания: an inner join будет работать так же хорошо, потому что в having предложении есть условие из review таблицы.