PostgREST с использованием лимита и смещения в подзапросах или CTE - PullRequest
0 голосов
/ 30 мая 2018

мы используем PostgREST в нашем проекте для некоторых довольно сложных представлений базы данных.

С некоторого момента, когда мы используем limit и offset (заголовки x-range или параметры запроса) с подвыборками, мы получаемочень высокое время отклика.

Из того, что мы прочитали, кажется, что это известная проблема, когда postgresql выполняет подвыборы даже для записей, которые не запрашиваются.Решением было бы немного поработать со смещением и пределом, поместив его в подвыбор или таблицу CTE.

Есть ли внутреннее значение GUC или что-то подобное, что мы можем использовать в представлениях базы данных, чтобыоптимизировать время отклика?У кого-нибудь есть подсказка о том, как этого добиться?

РЕДАКТИРОВАТЬ: , как предлагается здесь, некоторые подробности.Допустим, у нас есть отношения между продуктом и частями.Я хочу знать количество деталей для каждого продукта (это упрощенная версия представлений базы данных, которые мы представляем).

Есть два способа сделать это

A.Подвыбрать:

    SELECT products.id
            ,(
                    SELECT count(part_id) AS total
                    FROM parts
                    WHERE product_id = products.id
                    )
    FROM products limit 1000 OFFSET 99000

B.CTE:

    WITH parts_count
    AS (
            SELECT product_id
                    ,count(part_id) AS total
            FROM parts
            GROUP BY product_id
            ORDER BY product_id
            )
    SELECT products.id
            ,parts_count.total
    FROM products
    LEFT JOIN parts_count ON parts_count.product_id = product.id 
    LIMIT 1000     
    OFFSET 99000

Проблема с A заключается в том, что дополнительный выбор выполняется для каждой строки, поэтому, даже если я прочитал только 1000 записей, есть 100 000 подвыборов.

Проблема с B заключается в том, что объединение с таблицей parts_count занимает очень много времени, поскольку в нем 100 000 записей (хотя запрос with занимает всего 200 мс! Для 2000 записей).В идеале я хотел бы ограничить таблицу parts_count тем же пределом и смещением, что и у основного запроса, но я не могу сделать это в PostgREST, поскольку он просто добавляет предел и смещение в конце, у меня нет доступа к этим параметрам внутри С запрос

1 Ответ

0 голосов
/ 30 мая 2018

Неизбежно, что высокий OFFSET приводит к плохой производительности.

Нет другого способа вычислить OFFSET, кроме как сканировать и отбрасывать все строки, пока не будет достигнуто смещение, и нет базы данных вмир будет быстрым, если OFFSET высокий.

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

Если ваша цель - разбиение на страницы, то, как правило, нумерация клавиш - лучшее решение:

Вы добавляете предложение ORDER BY, соответствующее вашим требованиям, убедитесь, что естьуникальный ключ в предложении ORDER BY и запомните последнее найденное значение.Чтобы получить следующую страницу, добавьте условие WHERE с этими значениями.При правильной поддержке индекса это может быть очень быстро.

Для вашего запроса, возможно, более эффективная версия:

SELECT p.id
       count(parts.part_id) AS total
FROM (SELECT id FROM products
      LIMIT 1000 OFFSET 99000) p
   LEFT JOIN parts ON parts.product_id = p.id
GROUP BY p.id;

Довольно странно, что у вас нет ORDER BY, ноLIMIT и OFFSET.Это не имеет особого смысла.

...