Пагинация для сложных postgres запросов - PullRequest
0 голосов
/ 22 апреля 2020

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

Текущий запрос выполняется относительно быстро, но генерирует строки размером более 1 КБ, и мне нужно реализовать решение для разбивки на страницы.

В запросе относительно сложно получить всю информацию, необходимую для построения динамических c данных

FROM pulse_templates pt
INNER JOIN taggings ptags on ptags.taggable_type = 'PulseTemplate' AND ptags.taggable_id = 
pt.id AND ptags.context = 'available_for'
INNER JOIN schools s on s.id = 1
LEFT JOIN mascots m on m.id = s.mascot_id
LEFT JOIN pulse_designs pd on pd.id = m.silhouette_id
INNER JOIN colors_pulse_templates cpt ON cpt."pulse_template_id" = pt."id"
INNER JOIN items i on (pt.template_type = 'static' AND cpt."color_id" = i."primary_color_id") OR (pt.template_type = 'primary' AND s.primary_color_id = i.primary_color_id AND i.primary_color_id = cpt.color_id) or (pt.template_type = 'standard' AND i.primary_color_id = cpt.color_id AND (i.primary_color_id = s.primary_color_id OR i.primary_color_id = s.secondary_color_id OR i.primary_color_id = s.tertiary_color_id))
INNER JOIN taggings itags on itags.taggable_type = 'Item' AND itags.taggable_id = i.id AND itags.tag_id = ptags.tag_id AND ptags.context = 'available_for'
INNER JOIN tags tag on tag.id = itags.tag_id
INNER JOIN categories c on (c.id = i.category_id)
INNER JOIN pulse_products pp on pp.id = i.pulse_product_id
INNER JOIN product_lines pl on pl.id = i.product_line_id
WHERE
        s.id = 1 AND ((pt.all_identifiers LIKE '%mascot_name%' AND pd.id IS NOT NULL) OR pt.all_identifiers NOT LIKE '%mascot_name%')
GROUP BY s.id,pp.id,i.id,pt.id,pl.price

, а производительность допустима

Total query runtime: 1 secs 810 msec.
1365 rows affected.

Но когда я попытайтесь реализовать разбиение на страницы, используя LIMIT / OFFSET, оно выходит за пределы окна.

Total query runtime: 10 secs 737 msec.
25 rows affected.

С таким ударом по производительности я почти лучше перенести разбиение на страницы из базы данных и в код сервера.

Есть ли хороший способ реализации Pagination для общедоступного c веб-сайта, который не требует такого большого дополнительного времени обработки?

1 Ответ

0 голосов
/ 22 апреля 2020

Вы можете использовать WITH HOLD курсоры:

DECLARE c CURSOR WITH HOLD FOR SELECT ...;

Затем вы можете извлекать страницы с помощью

FETCH 25 FROM c;

Такие курсоры материализуются на сервере, поэтому вы должны обязательно закрыть курсор, когда вы закончите, чтобы освободить ресурсы:

CLOSE c;

Обратите внимание, что такие курсоры закрываются автоматически при завершении сеанса базы данных.

...