LINUX.ORG.RU

[SQL] Помогите оптимизировать запрос.

 


0

1

Необходимо выдать n элементов из таблицы some_table с максимальными id и различными значениями cat.
Сейчас задача решается так:
SELECT max(id) as id, cat FROM some_table GROUP BY cat ORDER BY id DESC LIMIT n;

На текущем размере таблицы это дает порядка 300 мс времени выполнения. Хотелось бы сильно уменьшить это время, если это возможно.

Ссылки приветствуются, т.к. мой скилл гуглоюзера оказался слаб.

Если что, БД - PostgreSQL 9.

★★★

Последнее исправление: unikoid (всего исправлений: 1)

Order by id точно нужен? Без него должно работать, и возможно, быстрее немного.

А вообще, можно однажды выбрать все такие записи в отдельную таблицу, и поддерживать ее по мере изменения some_table. Это будет в 90% случаев быстрейшее решение.

anonymous
()
Ответ на: комментарий от hidden_4003
EXPLAIN ANALYZE SELECT cat, max(id) AS id FROM some_table GROUP BY cat ORDER BY id DESC LIMIT 5;
                                                                QUERY PLAN                                                                
------------------------------------------------------------------------------------------------------------------------------------------
 Limit  (cost=6486.39..6486.41 rows=5 width=8) (actual time=299.385..299.394 rows=5 loops=1)
   ->  Sort  (cost=6486.39..6494.40 rows=3201 width=8) (actual time=299.381..299.384 rows=5 loops=1)
         Sort Key: (max(id))
         Sort Method:  top-N heapsort  Memory: 17kB
         ->  HashAggregate  (cost=6393.22..6433.23 rows=3201 width=8) (actual time=291.330..295.401 rows=4101 loops=1)
               ->  Seq Scan on some_table  (cost=0.00..5787.81 rows=121081 width=8) (actual time=0.038..122.959 rows=121081 loops=1)
 Total runtime: 299.529 ms
(7 rows)
unikoid ★★★
() автор топика
Ответ на: комментарий от anonymous

>Order by id точно нужен?
Точно. Без него совсем другие результаты.

А вообще, можно однажды выбрать все такие записи в отдельную таблицу, и поддерживать ее по мере изменения some_table. Это будет в 90% случаев быстрейшее решение.

Это да, но подумалось, что может быть можно как-то все-таки запрос ускорить.

unikoid ★★★
() автор топика
Ответ на: комментарий от hidden_4003

[code]
ERROR: column «some_table.id» must appear in the GROUP BY clause or be used in an aggregate function
СТРОКА 1:select distinct cat, id FROM some_table GROUP BY ...
[/code]

Вот то, что он выдал. Если обернуть id в аggregate function (max) - выдает то же, но даже чуть медленней.
Да, а в чем странность-то?

unikoid ★★★
() автор топика
Ответ на: комментарий от unikoid

запрос верный, быстрее его не написать. либо временная таблица/вьюха с результатами, либо тонкости пг. кстати, в пг аналитические функции есть?

belka
()
Ответ на: комментарий от unikoid

Похоже, что поможет только метод с отдельной таблицей, предложенный анонимусом

unC0Rr ★★★★★
()
Ответ на: комментарий от hidden_4003

>Извиняюсь, видимо я еще не проснулся. Конечно же GROUP BY тоже выкинуть
Это тоже не то, т.к. возвращает ряды с уникальными cat И id, то есть все (т.к. id - уникален в любом случае). Короче говоря, видимо действительно придется делать в отдельной таблице.

unikoid ★★★
() автор топика
Ответ на: комментарий от unikoid

Да, а в чем странность-то?

Если у Вас id это уникальный номер который возрастает то group by и max не нужен достаточно order by, если же нет то судя по explain не хватает индекса по cat,id.

hidden_4003
()
Ответ на: комментарий от unikoid

Да, мой вариант сработает только если выкинуть id. Разве что брать больше 5 и фильтровать уже не в БД судя по запросу оно аж 8000 строк вытягивает. С другой стороны, а 2 запроса сначала извлечь категории а потом max(id) к ним ?

select cat, max(id) as id FROM some_table WHERE cat IN (select distinct cat FROM some_table ORDER BY id DESC LIMIT 5) ORDER BY id;

hidden_4003
()
Ответ на: комментарий от hidden_4003

в постгресе GROUP BY будет быстрее DISTINCT, и ключ по полю не ускорит GROUP BY, там какие-то тонкости на этот счёт, из-за которых постгрес всё равно все данные из таблицы выгребает

unC0Rr ★★★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.