Оболочка внешних данных
Как правило, объединения или любые производные таблицы из подзапросов или 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)
...
Как правило, в этом нет необходимости, если сервер БД настроен правильно и статистика столбцов актуальна. Но есть угловые случаи с неравномерным распределением данных ...