Как заставить оценку подзапроса до присоединения / отправки на сторонний сервер - PullRequest
2 голосов
/ 29 апреля 2020

Предположим, я хочу запросить большую таблицу с несколькими WHERE фильтрами. Я использую Postgres 11 и чужую таблицу; обёртка сторонних данных (FDW) clickhouse_fdw. Но меня также интересует общее решение.

Я могу сделать это следующим образом:

SELECT id,c1,c2,c3 from big_table where id=3 and c1=2

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

Вышеописанное работает так же, если я напишу:

SELECT id,c1,c2,c3 from big_table where id IN (3,4,5) and c1=2

Т.е. вся фильтрация отправляется в нисходящем направлении.

Однако, если фильтрация, которую я пытаюсь сделать, немного сложнее:

SELECT bt.id,bt.c1,bt.c2,bt.c3
from big_table bt
join lookup_table l on bt.id=l.id
where c1=2 and l.x=5

, тогда планировщик запросов решает отфильтровать c1=2 удаленно, но применить другой фильтр локально.

В моем случае использования, вычисление, которое id s имеет сначала l.x=5, а затем отправка их на удаленную фильтрацию будет происходить гораздо быстрее, поэтому я попытался написать это следующим образом:

SELECT id,c1,c2,c3
from big_table
where c1=2
and id IN (select id from lookup_table where x=5)

Однако планировщик запросов все еще решает выполнить второй фильтр локально для ВСЕХ результатов из big_table, которые удовлетворяют c1=2, что очень медленно.

Есть ли какой-то способ, которым я могу "форсировать" (select id from lookup_table where x=5) для предварительного расчета и отправки часть удаленного фильтра?

1 Ответ

2 голосов
/ 29 апреля 2020

Оболочка внешних данных

Как правило, объединения или любые производные таблицы из подзапросов или CTE недоступны на стороннем сервере и должны выполняться локально. Т.е. все строки, оставшиеся после простого предложения WHERE в вашем примере, должны быть получены и обработаны локально, как вы наблюдали.

Если все остальное не удалось, вы можете выполнить подзапрос SELECT id FROM lookup_table WHERE x = 5 и объединить результаты в запросе. string.

Более удобно, вы можете автоматизировать это с помощью Dynami c SQL и EXECUTE в функции PL / pg SQL. Как:

CREATE OR REPLACE FUNCTION my_func(_c1 int, _l_id int)
   RETURNS TABLE(id int, c1 int, c2 int, c3 int) AS
$func$
BEGIN
   RETURN QUERY EXECUTE
     'SELECT id,c1,c2,c3 FROM big_table
      WHERE  c1 = $1
      AND    id = ANY ($2)'
   USING _c1
       , ARRAY(SELECT l.id FROM lookup_table l WHERE l.x = _l_id);
END
$func$  LANGUAGE plpgsql;

Связанный:

Или попробовать этот поиск по SO .

Или вы можете использовать мета-команду \gexec в psql. См .:

Или это может работа: (обратная связь говорит, что не работает .)

SELECT id,c1,c2,c3
FROM   big_table
WHERE  c1 = 2
AND    id = ANY (ARRAY(SELECT id FROM lookup_table WHERE x = 5));

При локальном тестировании я получаю план запроса, подобный следующему:

Index Scan using big_table_idx on big_table (cost= ...)
  Index Cond: (id = ANY (<b>$0</b>))
  Filter: (c1 = 2)
  InitPlan 1 (returns <b>$0</b>)
    ->  Seq Scan on lookup_table  (cost= ...)
          Filter: (x = 5)

Смелый акцент мой.

Параметр $0 в плане внушает надежду. Сгенерированный массив может быть чем-то, что Postgres может передавать удаленно. Я не вижу подобного плана ни с одной из ваших других попыток, или с некоторыми другими, которые я пробовал сам. Можете ли вы проверить с вашим FDW?

Смежный вопрос, касающийся postgres_fdw:

Общая техника в SQL

Это другая история. Просто используйте CTE. Но я не ожидаю, что это поможет с FDW.

WITH cte AS (SELECT id FROM lookup_table WHERE x = 5)
SELECT id,c1,c2,c3
FROM   big_table b
JOIN   cte USING (id)
WHERE  b.c1 = 2;

PostgreSQL 12 измененное (улучшенное) поведение, так что CTE могут быть встроены как подзапросы, учитывая некоторые предварительные условия , Но, цитируя руководство :

Вы можете отменить это решение, указав MATERIALIZED для принудительного отдельного вычисления запроса WITH

Итак:

WITH cte AS MATERIALIZED (SELECT id FROM lookup_table WHERE x = 5)
...

Как правило, в этом нет необходимости, если сервер БД настроен правильно и статистика столбцов актуальна. Но есть угловые случаи с неравномерным распределением данных ...

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