Как быстро сделать подзапрос - PullRequest
2 голосов
/ 09 февраля 2011

для обзора автора мы ищем запрос, который покажет всем авторам, включая их лучшую книгу. Проблема этого запроса в том, что ему не хватает скорости. Существует всего около 1500 авторов, и запрос на создание обзора в настоящее время занимает 20 секунд.

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

select
    person.id as pers_id,
    person.firstname,
    person.suffix,
person.lastname,
    thriller.title,
    year(thriller.orig_pubdate) as year,
    thriller.id as thrill_id,
    count(user_rating.id) as nr,
    AVG(user_rating.rating) as avgrating
from 
    thriller 
inner join 
    thriller_form 
    on thriller_form.thriller_id = thriller.id
inner join 
    thriller_person 
    on thriller_person.thriller_id = thriller.id 
    and thriller_person.person_type_id = 1 
inner join 
    person 
    on person.id = thriller_person.person_id
left outer join
    user_rating
    on user_rating.thriller_id = thriller.id 
    and user_rating.rating_type_id = 1
where thriller.id in
    (select top 1 B.id from thriller as B
    inner join thriller_person as C on B.id=C.thriller_id
    and person.id=C.person_id)
group by
    person.firstname,
    person.suffix,
    person.lastname,
    thriller.title,
    year(thriller.orig_pubdate),
    thriller.id,
    person.id
order by
    person.lastname

Однако, если мы сделаем подзапрос немного более сложным, выбрав книгу со средним рейтингом, для генерации набора результатов потребуется целых 20 секунд. Запрос будет выглядеть следующим образом:

select
    person.id as pers_id,
    person.firstname,
    person.suffix,
    person.lastname,
    thriller.title,
    year(thriller.orig_pubdate) as year,
    thriller.id as thrill_id,
    count(user_rating.id) as nr,
    AVG(user_rating.rating) as avgrating
from 
    thriller 
inner join 
    thriller_form 
    on thriller_form.thriller_id = thriller.id
inner join 
    thriller_person 
    on thriller_person.thriller_id = thriller.id 
    and thriller_person.person_type_id = 1 
inner join 
    person 
    on person.id = thriller_person.person_id
left outer join
    user_rating
    on user_rating.thriller_id = thriller.id 
    and user_rating.rating_type_id = 1
where thriller.id in
    (select top 1 B.id from thriller as B
    inner join thriller_person as C on B.id=C.thriller_id
    and person.id=C.person_id
    inner join user_rating as D on B.id=D.thriller_id
    group by B.id
    order by AVG(D.rating))
group by
    person.firstname,
    person.suffix,
    person.lastname,
    thriller.title,
    year(thriller.orig_pubdate),
    thriller.id,
    person.id
    order by
    person.lastname

Кто-нибудь получил хорошее предложение, чтобы ускорить этот запрос?

1 Ответ

2 голосов
/ 09 февраля 2011

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

Может быть целесообразно использовать временную таблицу в качестве хранилища средних значений.

...