PostgreSQL
 sql >> база данни >  >> RDS >> PostgreSQL

Как да принудим оценка на подзаявката преди присъединяване/натискане надолу към чужд сървър

Обвивка на чужди данни

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

Ако всичко друго не успее, можете да изпълните подзаявката SELECT id FROM lookup_table WHERE x = 5 и конкатенира резултатите в низа на заявката.

По-удобно е, че можете да автоматизирате това с динамичен SQL и EXECUTE във функция PL/pgSQL. Като:

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;

Свързано:

  • Име на таблица като параметър на функцията на PostgreSQL

Или опитайте това търсене на SO.

Или можете да използвате метакомандата \gexec в psql. Вижте:

  • Филтрирайте имената на колони от съществуваща таблица за SQL DDL израз

Или това може да работи: (Отзивите казват, че не работи .)

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 ($0))
  Filter: (c1 = 2)
  InitPlan 1 (returns $0)
    ->  Seq Scan on lookup_table  (cost= ...)
          Filter: (x = 5)

Удебелен акцент мой.

Параметърът $0 в плана вдъхва надежда. Генерираният масив може да е нещо, което Postgres може да предаде, за да се използва отдалечено. Не виждам подобен план с други твои опити или други, които опитах сам. Можете ли да тествате с вашия fdw?

Свързан въпрос относно 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)
...

Обикновено нищо от това не трябва да е необходимо, ако вашият DB сървър е конфигуриран правилно и статистиката на колоните е актуална. Но има ъглови случаи с неравномерно разпределение на данните ...




  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. вземете таблица JOIN като масив от резултати с PostgreSQL/NodeJS

  2. PostgreSQL:Променете OWNER на всички таблици едновременно в PostgreSQL

  3. Съвети за съхраняване на резервни копия на PostgreSQL в Google Cloud (GCP)

  4. Python/postgres/psycopg2:получаване на ID на току-що вмъкнатия ред

  5. Как да работите с PostgreSQL бази данни