Помогите оптимизировать запрос

Темы, не касающиеся фреймворка, но относящиеся к программированию в целом.
Ответить
big_mike
Сообщения: 113
Зарегистрирован: 2013.02.26, 01:12

Помогите оптимизировать запрос

Сообщение big_mike »

Есть следующий запрос:

Код: Выделить всё

SELECT `t`.`id` AS `t0_c0`, `t`.`cat_id` AS `t0_c3`, `t`.`type_id` AS `t0_c19`, `t`.`title` AS `t0_c1`, `t`.`slug` AS `t0_c2`, `t`.`content_short` AS `t0_c4`, `t`.`create_time` AS `t0_c6`, `category`.`id` AS `t1_c0`, `category`.`title` AS `t1_c1`, `category`.`slug` AS `t1_c2`, `type`.`title` AS `t2_c1`, `type`.`slug` AS `t2_c12`, `type`.`column_placement` AS `t2_c17`, `type`.`id` AS `t2_c0` FROM `items` `t` LEFT JOIN items f2 ON (t.type_id = f2.type_id AND t.create_time >= f2.create_time) LEFT OUTER JOIN `category` `category` ON (`t`.`cat_id`=`category`.`id`) LEFT OUTER JOIN `type` `type` ON (`t`.`type_id`=`type`.`id`) GROUP BY t.type_id, t.create_time HAVING (COUNT(*) <= 5)
Explain:
Изображение
Время: 35796.9 ms
Аватара пользователя
samdark
Администратор
Сообщения: 9489
Зарегистрирован: 2009.04.02, 13:46
Откуда: Воронеж
Контактная информация:

Re: Помогите оптимизировать запрос

Сообщение samdark »

Индексы по всем полям, которые в JOIN, есть?
big_mike
Сообщения: 113
Зарегистрирован: 2013.02.26, 01:12

Re: Помогите оптимизировать запрос

Сообщение big_mike »

Добавил индекс (type_id, create_time), стало быстрее, но все равно не то, что хочется.
Аватара пользователя
samdark
Администратор
Сообщения: 9489
Зарегистрирован: 2009.04.02, 13:46
Откуда: Воронеж
Контактная информация:

Re: Помогите оптимизировать запрос

Сообщение samdark »

Радикальное решение — чуть денормализовать. Хранить количество полем и обновлять при изменениях, а не считать в HAVING.
big_mike
Сообщения: 113
Зарегистрирован: 2013.02.26, 01:12

Re: Помогите оптимизировать запрос

Сообщение big_mike »

А тут вся суть в том, что нужно выбрать по 5 записей каждого типа, для это тут COUNT(). Есть еще вариант с mysql переменными, там запрос вроде быстрее проходит. Как-то вот так:

Код: Выделить всё

set @num := 0, @type := 0;
select t.type_id, t.title, t.create_time,
      @num := if(@type = t.type_id, @num + 1, 1) as row_number,
      @type := t.type_id as dummy, obtype.title, cat.title
from items t force index(type_index)
LEFT JOIN type obtype ON t.type_id = obtype.id
LEFT JOIN category cat ON t.cat_id = cat.id
group by t.type_id, t.create_time, t.title 
having row_number <= 5;
4500+ записей, время: 0.066
big_mike
Сообщения: 113
Зарегистрирован: 2013.02.26, 01:12

Re: Помогите оптимизировать запрос

Сообщение big_mike »

Только как это перенести теперь в критерию не знаю.
big_mike
Сообщения: 113
Зарегистрирован: 2013.02.26, 01:12

Re: Помогите оптимизировать запрос

Сообщение big_mike »

Скажите, как можно в этом запросе еще сделать сортировку перед группировкой? А то сейчас выводятся не последние записи, а первые.
Аватара пользователя
samdark
Администратор
Сообщения: 9489
Зарегистрирован: 2009.04.02, 13:46
Откуда: Воронеж
Контактная информация:

Re: Помогите оптимизировать запрос

Сообщение samdark »

Подзапросом.
big_mike
Сообщения: 113
Зарегистрирован: 2013.02.26, 01:12

Re: Помогите оптимизировать запрос

Сообщение big_mike »

Может кому пригодится. Запрос группирует по 5 последних записей каждого типа, отсортированных по дате внутри группы:

Код: Выделить всё

select id,type_id,title, create_time,cat_id,content_short
                from
                (
                  SELECT id,type_id,title, create_time,cat_id,content_short,
                    @row:=case when @prev=type_id then @row else 0 end +1 row_number,
                    @prev:=type_id
                  FROM items t
                  CROSS JOIN (select @row:=0, @prev:=null) c
                  order by type_id, create_time desc
                ) src
                where row_number <= 5
                order by type_id, create_time
Ответить