ื ื™ืชื•ื— ืชืคืขื•ืœื™ ื‘ืืจื›ื™ื˜ืงื˜ื•ืจืช ืฉื™ืจื•ืช ืžื™ืงืจื•: ืขื–ืจื” ื•ื”ื ื—ื™ื” ืœ- Postgres FDW

ืœืืจื›ื™ื˜ืงื˜ื•ืจืช Microservice, ื›ืžื• ืœื›ืœ ื“ื‘ืจ ื‘ืขื•ืœื ื”ื–ื”, ื™ืฉ ื™ืชืจื•ื ื•ืช ื•ื—ืกืจื•ื ื•ืช. ื—ืœืง ืžื”ืชื”ืœื™ื›ื™ื ื”ื•ืคื›ื™ื ืขื ื–ื” ืœืงืœื™ื ื™ื•ืชืจ, ืื—ืจื™ื ืงืฉื™ื ื™ื•ืชืจ. ื•ืœืžืขืŸ ืžื”ื™ืจื•ืช ื”ืฉื™ื ื•ื™ ื•ืžื“ืจื’ื™ื•ืช ื˜ื•ื‘ื” ื™ื•ืชืจ, ืืชื” ืฆืจื™ืš ืœื”ืงืจื™ื‘. ืื—ื“ ืžื”ื ื”ื•ื ื”ืžื•ืจื›ื‘ื•ืช ื”ื”ื•ืœื›ืช ื•ื’ื•ื‘ืจืช ืฉืœ ืื ืœื™ื˜ื™ืงื”. ืื ื‘ืžื•ื ื•ืœื™ื˜ ื ื™ืชืŸ ืœืฆืžืฆื ืืช ื›ืœ ื”ืื ืœื™ื˜ื™ืงื” ื”ืชืคืขื•ืœื™ืช ืœืฉืื™ืœืชื•ืช SQL ืœืขืชืง ืื ืœื™ื˜ื™, ืื– ื‘ืืจื›ื™ื˜ืงื˜ื•ืจืช ืจื™ื‘ื•ื™ ืฉื™ืจื•ืชื™ื ืœื›ืœ ืฉื™ืจื•ืช ื™ืฉ ืžืกื“ ื ืชื•ื ื™ื ืžืฉืœื• ื•ื ืจืื” ืฉืื™ ืืคืฉืจ ืœืขืฉื•ืช ืฉืื™ืœืชื” ืื—ืช (ืื• ืฉืื•ืœื™ ื›ืŸ?). ืœืžื™ ืฉืžืชืขื ื™ื™ืŸ ืื™ืš ืคืชืจื ื• ืืช ื‘ืขื™ื™ืช ื”ื ื™ืชื•ื— ื”ืชืคืขื•ืœื™ ื‘ื—ื‘ืจื” ืฉืœื ื• ื•ืื™ืš ืœืžื“ื ื• ืœื—ื™ื•ืช ืขื ื”ืคืชืจื•ืŸ ื”ื–ื” - ื‘ืจื•ืš ื”ื‘ื.

ื ื™ืชื•ื— ืชืคืขื•ืœื™ ื‘ืืจื›ื™ื˜ืงื˜ื•ืจืช ืฉื™ืจื•ืช ืžื™ืงืจื•: ืขื–ืจื” ื•ื”ื ื—ื™ื” ืœ- Postgres FDW
ืฉืžื™ ืคืื‘ืœ ืกื™ื•ื•ืืฉ, ื‘-DomClick ืื ื™ ืขื•ื‘ื“ ื‘ืฆื•ื•ืช ืฉืื—ืจืื™ ืขืœ ืชื—ื–ื•ืงืช ืžื—ืกืŸ ื”ื ืชื•ื ื™ื ื”ืื ืœื™ื˜ื™ื™ื. ื‘ืื•ืคืŸ ืงื•ื ื‘ื ืฆื™ื•ื ืœื™, ื ื™ืชืŸ ืœืกื•ื•ื’ ืืช ื”ืคืขื™ืœื•ื™ื•ืช ืฉืœื ื• ื›ื”ื ื“ืกืช ื ืชื•ื ื™ื, ืืš ืœืžืขืฉื”, ืžื’ื•ื•ืŸ ื”ืžืฉื™ืžื•ืช ืจื—ื‘ ื”ืจื‘ื” ื™ื•ืชืจ. ื™ืฉื ื ืชืงืŸ ETL/ELT ืœื”ื ื“ืกืช ื ืชื•ื ื™ื, ืชืžื™ื›ื” ื•ื”ืชืืžื” ืฉืœ ื›ืœื™ื ืœื ื™ืชื•ื— ื ืชื•ื ื™ื ื•ืคื™ืชื•ื— ื›ืœื™ื ืžืฉืœืš. ื‘ืžื™ื•ื—ื“ ืขื‘ื•ืจ ื“ื™ื•ื•ื— ืชืคืขื•ืœื™ ื”ื—ืœื˜ื ื• "ืœื”ืขืžื™ื“ ืคื ื™ื" ืฉื™ืฉ ืœื ื• ืžื•ื ื•ืœื™ื˜ ื•ืœืชืช ืœืื ืœื™ืกื˜ื™ื ืžืกื“ ื ืชื•ื ื™ื ืื—ื“ ืฉื™ื›ื™ืœ ืืช ื›ืœ ื”ื ืชื•ื ื™ื ืฉื”ื ืฆืจื™ื›ื™ื.

ื‘ืื•ืคืŸ ื›ืœืœื™, ืฉืงืœื ื• ืืคืฉืจื•ื™ื•ืช ืฉื•ื ื•ืช. ืืคืฉืจ ื”ื™ื” ืœื‘ื ื•ืช ืžืื’ืจ ืžืœื - ืืคื™ืœื• ื ื™ืกื™ื ื•, ืื‘ืœ ืœืžืขืŸ ื”ืืžืช, ืœื ื”ืฆืœื—ื ื• ืœืฉืœื‘ ืฉื™ื ื•ื™ื™ื ืชื›ื•ืคื™ื ืœืžื“ื™ ื‘ืœื•ื’ื™ืงื” ืขื ื”ืชื”ืœื™ืš ื”ืื™ื˜ื™ ืœืžื“ื™ ืฉืœ ื‘ื ื™ื™ืช ืžืื’ืจ ื•ื‘ื™ืฆื•ืข ืฉื™ื ื•ื™ื™ื ื‘ื• (ืื ืžื™ืฉื”ื• ื”ืฆืœื™ื— , ื›ืชื•ื‘ ื‘ืชื’ื•ื‘ื•ืช ืื™ืš). ืืคืฉืจ ื”ื™ื” ืœื•ืžืจ ืœืื ืœื™ืกื˜ื™ื: "ื—ื‘ืจ'ื”, ืœืžื“ื• ืคื™ืชื•ืŸ ื•ืœื›ื• ืœื”ืขืชืงื™ื ืื ืœื™ื˜ื™ื™ื", ืื‘ืœ ื–ื• ื“ืจื™ืฉื” ื ื•ืกืคืช ืœื’ื™ื•ืก, ื•ื ืจืื” ื”ื™ื” ืฉืฆืจื™ืš ืœื”ื™ืžื ืข ืžื›ืš ื‘ืžื™ื“ืช ื”ืืคืฉืจ. ื”ื—ืœื˜ื ื• ืœื ืกื•ืช ืœื”ืฉืชืžืฉ ื‘ื˜ื›ื ื•ืœื•ื’ื™ื™ืช FDW (Foreign Data Wrapper): ื‘ืขืฆื, ืžื“ื•ื‘ืจ ื‘-dblink ืกื˜ื ื“ืจื˜ื™, ืฉื ืžืฆื ื‘ืชืงืŸ SQL, ืื‘ืœ ืขื ืžืžืฉืง ืžืฉืœื• ื”ืจื‘ื” ื™ื•ืชืจ ื ื•ื—. ืขืœ ืกืžืš ื–ื” ืขืฉื™ื ื• ืคืชืจื•ืŸ ืฉื‘ืกื•ืคื• ืฉืœ ื“ื‘ืจ ืชืคืก ื•ื”ืกืชื“ืจื ื• ืขืœื™ื•. ื”ืคืจื˜ื™ื ืฉืœื• ื”ื ื ื•ืฉื ืฉืœ ืžืืžืจ ื ืคืจื“, ื•ืื•ืœื™ ื™ื•ืชืจ ืžืื—ื“, ืฉื›ืŸ ืื ื™ ืจื•ืฆื” ืœื“ื‘ืจ ืขืœ ื”ืจื‘ื”: ืžืกื ื›ืจื•ืŸ ืกื›ื™ืžื•ืช ืžืกื“ ื ืชื•ื ื™ื ื•ืขื“ ื‘ืงืจืช ื’ื™ืฉื” ื•ื“ื”-ืคืจืกื•ื ืœื™ื–ืฆื™ื” ืฉืœ ื ืชื•ื ื™ื ืื™ืฉื™ื™ื. ื›ืžื• ื›ืŸ, ื™ืฉ ืฆื•ืจืš ืœื”ืกืชื™ื™ื’ ืฉืคืชืจื•ืŸ ื–ื” ืื™ื ื• ืชื—ืœื™ืฃ ืœืžืื’ืจื™ ืžื™ื“ืข ื•ืžืื’ืจื™ื ืื ืœื™ื˜ื™ื™ื ืืžื™ืชื™ื™ื, ื”ื•ื ืคื•ืชืจ ืจืง ื‘ืขื™ื” ืกืคืฆื™ืคื™ืช.

ื‘ืจืžื” ื”ืขืœื™ื•ื ื” ื–ื” ื ืจืื” ื›ืš:

ื ื™ืชื•ื— ืชืคืขื•ืœื™ ื‘ืืจื›ื™ื˜ืงื˜ื•ืจืช ืฉื™ืจื•ืช ืžื™ืงืจื•: ืขื–ืจื” ื•ื”ื ื—ื™ื” ืœ- Postgres FDW
ื™ืฉื ื• ืžืกื“ ื ืชื•ื ื™ื PostgreSQL ืฉื‘ื• ืžืฉืชืžืฉื™ื ื™ื›ื•ืœื™ื ืœืื—ืกืŸ ืืช ื ืชื•ื ื™ ื”ืขื‘ื•ื“ื” ืฉืœื”ื, ื•ื”ื›ื™ ื—ืฉื•ื‘, ื”ืขืชืงื™ื ืื ืœื™ื˜ื™ื™ื ืฉืœ ื›ืœ ื”ืฉื™ืจื•ืชื™ื ืžื—ื•ื‘ืจื™ื ืœืžืกื“ ื ืชื•ื ื™ื ื–ื” ื‘ืืžืฆืขื•ืช FDW. ื–ื” ืžืืคืฉืจ ืœื›ืชื•ื‘ ืฉืื™ืœืชื” ืœื›ืžื” ืžืกื“ื™ ื ืชื•ื ื™ื, ื•ื–ื” ืœื ืžืฉื ื” ืžื” ื–ื”: PostgreSQL, MySQL, MongoDB ืื• ืžืฉื”ื• ืื—ืจ (ืงื•ื‘ืฅ, API, ืื ืคืชืื•ื ืื™ืŸ ืขื˜ื™ืคื” ืžืชืื™ืžื”, ืืชื” ื™ื›ื•ืœ ืœื›ืชื•ื‘ ืžืฉืœืš). ื•ื‘ื›ืŸ, ื”ื›ืœ ื ืจืื” ื ื”ื“ืจ! ืื ื—ื ื• ื ืคืจื“ื™ื?

ืื ื”ื›ืœ ื”ื™ื” ื ื’ืžืจ ื›ืœ ื›ืš ืžื”ืจ ื•ืคืฉื•ื˜, ืื–, ื›ื ืจืื”, ืœื ื”ื™ื” ืžืืžืจ.

ื—ืฉื•ื‘ ืฉื™ื”ื™ื” ื‘ืจื•ืจ ื›ื™ืฆื“ Postgres ืžืขื‘ื“ ื‘ืงืฉื•ืช ืœืฉืจืชื™ื ืžืจื•ื—ืงื™ื. ื–ื” ื ืจืื” ื”ื’ื™ื•ื ื™, ืื‘ืœ ืœืขืชื™ื ืงืจื•ื‘ื•ืช ืื ืฉื™ื ืœื ืฉืžื™ื ืœื‘ ืœื–ื”: Postgres ืžื—ืœืง ืืช ื”ื‘ืงืฉื” ืœื—ืœืงื™ื ืฉืžืชื‘ืฆืขื™ื ื‘ืื•ืคืŸ ืขืฆืžืื™ ื‘ืฉืจืชื™ื ืžืจื•ื—ืงื™ื, ืื•ืกืฃ ืืช ื”ื ืชื•ื ื™ื ื”ืืœื” ื•ืžื‘ืฆืข ืืช ื”ื—ื™ืฉื•ื‘ื™ื ื”ืกื•ืคื™ื™ื ื‘ืขืฆืžื•, ื›ืš ืฉืžื”ื™ืจื•ืช ื‘ื™ืฆื•ืข ื”ืฉืื™ืœืชื” ืชื”ื™ื” ืชืœื•ื™ื” ืžืื•ื“ ื‘ ืื™ืš ื–ื” ื›ืชื•ื‘. ืขื•ื“ ื™ืฉ ืœืฆื™ื™ืŸ: ื›ืฉื”ื ืชื•ื ื™ื ืžื’ื™ืขื™ื ืžืฉืจืช ืžืจื•ื—ืง ืื™ืŸ ืœื• ื™ื•ืชืจ ืื™ื ื“ืงืกื™ื, ืื™ืŸ ื“ื‘ืจ ืฉื™ืขื–ื•ืจ ืœืžืชื–ืžืŸ, ืœื›ืŸ ืจืง ืื ื—ื ื• ื‘ืขืฆืžื ื• ื™ื›ื•ืœื™ื ืœืขื–ื•ืจ ื•ืœื™ื™ืขืฅ ืœื•. ื•ืขืœ ื–ื” ื‘ื“ื™ื•ืง ืื ื™ ืจื•ืฆื” ืœื“ื‘ืจ ื‘ื™ืชืจ ืคื™ืจื•ื˜.

ืฉืื™ืœืชื” ืคืฉื•ื˜ื” ื•ืชื•ื›ื ื™ืช ืื™ืชื”

ื›ื“ื™ ืœื”ืจืื•ืช ื›ื™ืฆื“ Postgres ืžื‘ืฆืข ืฉืื™ืœืชื•ืช ื‘ื˜ื‘ืœื” ืฉืœ 6 ืžื™ืœื™ื•ืŸ ืฉื•ืจื•ืช ื‘ืฉืจืช ืžืจื•ื—ืง, ื”ื‘ื” ื ืกืชื›ืœ ืขืœ ืชื•ื›ื ื™ืช ืคืฉื•ื˜ื”.

explain analyze verbose  
SELECT count(1)
FROM fdw_schema.table;

Aggregate  (cost=418383.23..418383.24 rows=1 width=8) (actual time=3857.198..3857.198 rows=1 loops=1)
  Output: count(1)
  ->  Foreign Scan on fdw_schema."table"  (cost=100.00..402376.14 rows=6402838 width=0) (actual time=4.874..3256.511 rows=6406868 loops=1)
        Output: "table".id, "table".is_active, "table".meta, "table".created_dt
        Remote SQL: SELECT NULL FROM fdw_schema.table
Planning time: 0.986 ms
Execution time: 3857.436 ms

ืฉื™ืžื•ืฉ ื‘ืžืฉืคื˜ VERBOSE ืžืืคืฉืจ ืœื ื• ืœืจืื•ืช ืืช ื”ืฉืื™ืœืชื” ืฉืชื™ืฉืœื— ืœืฉืจืช ื”ืžืจื•ื—ืง ื•ืืช ืชื•ืฆืื•ืชื™ื” ื ืงื‘ืœ ืœื”ืžืฉืš ืขื™ื‘ื•ื“ (ืฉื•ืจืช RemoteSQL).

ื‘ื•ืื• ื ืœืš ืงืฆืช ื™ื•ืชืจ ืจื—ื•ืง ื•ื ื•ืกื™ืฃ ื›ืžื” ืžืกื ื ื™ื ืœื‘ืงืฉืชื ื•: ืื—ื“ ืขื‘ื•ืจ ื‘ื•ืœื™ืื ื™ ืฉื“ื”, ืื—ื“ ืœืคื™ ืื™ืจื•ืข ื—ื•ืชื ื‘ืžืจื•ื•ื— ื•ืื—ื“ ืื—ืจ jsonb.

explain analyze verbose
SELECT count(1)
FROM fdw_schema.table 
WHERE is_active is True
AND created_dt BETWEEN CURRENT_DATE - INTERVAL '7 month' 
AND CURRENT_DATE - INTERVAL '6 month'
AND meta->>'source' = 'test';

Aggregate  (cost=577487.69..577487.70 rows=1 width=8) (actual time=27473.818..25473.819 rows=1 loops=1)
  Output: count(1)
  ->  Foreign Scan on fdw_schema."table"  (cost=100.00..577469.21 rows=7390 width=0) (actual time=31.369..25372.466 rows=1360025 loops=1)
        Output: "table".id, "table".is_active, "table".meta, "table".created_dt
        Filter: (("table".is_active IS TRUE) AND (("table".meta ->> 'source'::text) = 'test'::text) AND ("table".created_dt >= (('now'::cstring)::date - '7 mons'::interval)) AND ("table".created_dt <= ((('now'::cstring)::date)::timestamp with time zone - '6 mons'::interval)))
        Rows Removed by Filter: 5046843
        Remote SQL: SELECT created_dt, is_active, meta FROM fdw_schema.table
Planning time: 0.665 ms
Execution time: 27474.118 ms

ื›ืืŸ ื˜ืžื•ื ื” ื”ื ืงื•ื“ื” ืฉืขืœื™ืš ืœืฉื™ื ืœื‘ ืืœื™ื” ื‘ืขืช ื›ืชื™ื‘ืช ืฉืื™ืœืชื•ืช. ื”ืžืกื ื ื™ื ืœื ื”ื•ืขื‘ืจื• ืœืฉืจืช ื”ืžืจื•ื—ืง, ืžื” ืฉืื•ืžืจ ืฉื›ื“ื™ ืœื”ืคืขื™ืœ ืื•ืชื•, Postgres ืฉื•ืœืฃ ืืช ื›ืœ 6 ืžื™ืœื™ื•ืŸ ื”ืฉื•ืจื•ืช ืขืœ ืžื ืช ืœืกื ืŸ ืื—ืจ ื›ืš ืžืงื•ืžื™ืช (Filter row) ื•ืœื‘ืฆืข ืฆื‘ื™ืจื”. ื”ืžืคืชื— ืœื”ืฆืœื—ื” ื”ื•ื ื›ืชื™ื‘ืช ืฉืื™ืœืชื” ื›ืš ืฉื”ืคื™ืœื˜ืจื™ื ื™ื•ืขื‘ืจื• ืœืžื›ื•ื ื” ื”ืžืจื•ื—ืงืช, ื•ืื ื• ืžืงื‘ืœื™ื ื•ืžืฆื‘ืจื™ื ืจืง ืืช ื”ืฉื•ืจื•ืช ื”ื“ืจื•ืฉื•ืช.

ื–ื” ืงืฆืช ื‘ื•ืœื™ืื ื™

ืขื ืฉื“ื•ืช ื‘ื•ืœื™ืื ื™ื™ื ื”ื›ืœ ืคืฉื•ื˜. ื‘ื‘ืงืฉื” ื”ืžืงื•ืจื™ืช, ื”ื‘ืขื™ื” ื ื‘ืขื” ืžื”ืžืคืขื™ืœ is. ืื ืชื—ืœื™ืฃ ืื•ืชื• ื‘ =, ืื– ื ืงื‘ืœ ืืช ื”ืชื•ืฆืื” ื”ื‘ืื”:

explain analyze verbose
SELECT count(1)
FROM fdw_schema.table
WHERE is_active = True
AND created_dt BETWEEN CURRENT_DATE - INTERVAL '7 month' 
AND CURRENT_DATE - INTERVAL '6 month'
AND meta->>'source' = 'test';

Aggregate  (cost=508010.14..508010.15 rows=1 width=8) (actual time=19064.314..19064.314 rows=1 loops=1)
  Output: count(1)
  ->  Foreign Scan on fdw_schema."table"  (cost=100.00..507988.44 rows=8679 width=0) (actual time=33.035..18951.278 rows=1360025 loops=1)
        Output: "table".id, "table".is_active, "table".meta, "table".created_dt
        Filter: ((("table".meta ->> 'source'::text) = 'test'::text) AND ("table".created_dt >= (('now'::cstring)::date - '7 mons'::interval)) AND ("table".created_dt <= ((('now'::cstring)::date)::timestamp with time zone - '6 mons'::interval)))
        Rows Removed by Filter: 3567989
        Remote SQL: SELECT created_dt, meta FROM fdw_schema.table WHERE (is_active)
Planning time: 0.834 ms
Execution time: 19064.534 ms

ื›ืคื™ ืฉื ื™ืชืŸ ืœืจืื•ืช, ื”ืžืกื ืŸ ื˜ืก ืœืฉืจืช ืžืจื•ื—ืง, ื•ื–ืžืŸ ื”ื‘ื™ืฆื•ืข ื”ืฆื˜ืžืฆื ืž-27 ืœ-19 ืฉื ื™ื•ืช.

ืจืื•ื™ ืœืฆื™ื™ืŸ ื›ื™ ื”ืžืคืขื™ืœ is ืฉื•ื ื” ืžื”ืžืคืขื™ืœ = ื›ื™ ื–ื” ื™ื›ื•ืœ ืœืขื‘ื•ื“ ืขื ื”ืขืจืš Null. ื–ื” ืื•ืžืจ ืฉ ืœื ื ื›ื•ืŸ ื™ืฉืื™ืจ ืืช ื”ืขืจื›ื™ื False ื•-Null ื‘ืžืกื ืŸ, ื•ืื™ืœื• != ื ื›ื•ืŸ ื™ืฉืื™ืจ ืจืง ืขืจื›ื™ ืฉืงืจ. ืœื›ืŸ, ื‘ืขืช ื”ื—ืœืคืช ื”ืžืคืขื™ืœ ืœื ื™ืฉ ืœื”ืขื‘ื™ืจ ืฉื ื™ ืชื ืื™ื ืขื ื”ืื•ืคืจื˜ื•ืจ OR ืœืžืกื ืŸ, ืœืžืฉืœ, WHERE (ืงื•ืœ != ื ื›ื•ืŸ) OR (ืงื•ืœ ื”ื•ื ืจื™ืง).

ืกื™ื“ืจื ื• ืืช ื”ื‘ื•ืœื™ืืŸ, ื‘ื•ืื• ื ืžืฉื™ืš ื”ืœืื”. ืœืขืช ืขืชื”, ื”ื‘ื” ื ื—ื–ื™ืจ ืืช ื”ืžืกื ืŸ ื”ื‘ื•ืœื™ืื ื™ ืœืฆื•ืจืชื• ื”ืžืงื•ืจื™ืช ื›ื“ื™ ืœืฉืงื•ืœ ื‘ืื•ืคืŸ ืขืฆืžืื™ ืืช ื”ื”ืฉืคืขื” ืฉืœ ืฉื™ื ื•ื™ื™ื ืื—ืจื™ื.

ื—ื•ืชืžืช ื–ืžืŸ? ื”ืจืฅ

ื‘ืื•ืคืŸ ื›ืœืœื™, ืœืขืชื™ื ืงืจื•ื‘ื•ืช ืืชื” ืฆืจื™ืš ืœื”ืชื ืกื•ืช ื›ื™ืฆื“ ืœื›ืชื•ื‘ ื‘ืฆื•ืจื” ื ื›ื•ื ื” ื‘ืงืฉื” ื”ื›ื•ืœืœืช ืฉืจืชื™ื ืžืจื•ื—ืงื™ื, ื•ืจืง ืื– ืœื—ืคืฉ ื”ืกื‘ืจ ืœืžื” ื–ื” ืงื•ืจื”. ืžืขื˜ ืžืื•ื“ ืžื™ื“ืข ืขืœ ื›ืš ื ื™ืชืŸ ืœืžืฆื•ื ื‘ืื™ื ื˜ืจื ื˜. ืœื›ืŸ, ื‘ื ื™ืกื•ื™ื™ื ืžืฆืื ื• ืฉืžืกื ืŸ ืชืืจื™ืš ืงื‘ื•ืข ื˜ืก ืœืฉืจืช ื”ืžืจื•ื—ืง ื‘ืจืขืฉ, ืื‘ืœ ื›ืฉืื ื—ื ื• ืจื•ืฆื™ื ืœื”ื’ื“ื™ืจ ืืช ื”ืชืืจื™ืš ื‘ืฆื•ืจื” ื“ื™ื ืžื™ืช, ืœืžืฉืœ, now() ืื• CURRENT_DATE, ื–ื” ืœื ืงื•ืจื”. ื‘ื“ื•ื’ืžื” ืฉืœื ื•, ื”ื•ืกืคื ื• ืžืกื ืŸ ื›ืš ืฉื”ืขืžื•ื“ื” create_at ื”ื›ื™ืœื” ื ืชื•ื ื™ื ื‘ื“ื™ื•ืง ืขื‘ื•ืจ ื—ื•ื“ืฉ ืื—ื“ ื‘ืขื‘ืจ (ื‘ื™ืŸ CURRENT_DATE - INTERVAL '1 ื—ื•ื“ืฉื™ื' ื•-CURRENT_DATE - INTERVAL '7 ื—ื•ื“ืฉื™ื'). ืžื” ืขืฉื™ื ื• ื‘ืžืงืจื” ื”ื–ื”?

explain analyze verbose
SELECT count(1)
FROM fdw_schema.table 
WHERE is_active is True
AND created_dt >= (SELECT CURRENT_DATE::timestamptz - INTERVAL '7 month') 
AND created_dt <(SELECT CURRENT_DATE::timestamptz - INTERVAL '6 month')
AND meta->>'source' = 'test';

Aggregate  (cost=306875.17..306875.18 rows=1 width=8) (actual time=4789.114..4789.115 rows=1 loops=1)
  Output: count(1)
  InitPlan 1 (returns $0)
    ->  Result  (cost=0.00..0.02 rows=1 width=8) (actual time=0.007..0.008 rows=1 loops=1)
          Output: ((('now'::cstring)::date)::timestamp with time zone - '7 mons'::interval)
  InitPlan 2 (returns $1)
    ->  Result  (cost=0.00..0.02 rows=1 width=8) (actual time=0.002..0.002 rows=1 loops=1)
          Output: ((('now'::cstring)::date)::timestamp with time zone - '6 mons'::interval)
  ->  Foreign Scan on fdw_schema."table"  (cost=100.02..306874.86 rows=105 width=0) (actual time=23.475..4681.419 rows=1360025 loops=1)
        Output: "table".id, "table".is_active, "table".meta, "table".created_dt
        Filter: (("table".is_active IS TRUE) AND (("table".meta ->> 'source'::text) = 'test'::text))
        Rows Removed by Filter: 76934
        Remote SQL: SELECT is_active, meta FROM fdw_schema.table WHERE ((created_dt >= $1::timestamp with time zone)) AND ((created_dt < $2::timestamp with time zone))
Planning time: 0.703 ms
Execution time: 4789.379 ms

ืืžืจื ื• ืœืžืชื›ื ืŸ ืœื—ืฉื‘ ืืช ื”ืชืืจื™ืš ื‘ืฉืื™ืœืชืช ื”ืžืฉื ื” ืžืจืืฉ ื•ืœื”ืขื‘ื™ืจ ืืช ื”ืžืฉืชื ื” ื”ืžื•ื›ืŸ ืœืžืกื ืŸ. ื•ื”ืจืžื– ื”ื–ื” ื ืชืŸ ืœื ื• ืชื•ืฆืื” ืžืฆื•ื™ื ืช, ื”ื‘ืงืฉื” ื”ืคื›ื” ืœืžื”ื™ืจื” ื›ืžืขื˜ ืคื™ 6!

ืฉื•ื‘, ื—ืฉื•ื‘ ืœื”ื™ื–ื”ืจ ื›ืืŸ: ืกื•ื’ ื”ื ืชื•ื ื™ื ื‘ืฉืื™ืœืชืช ื”ืžืฉื ื” ื—ื™ื™ื‘ ืœื”ื™ื•ืช ื–ื”ื” ืœื–ื” ืฉืœ ื”ืฉื“ื” ืขืœื™ื• ืื ื• ืžืกื ื ื™ื, ืื—ืจืช ื”ืžืชื›ื ืŸ ื™ื—ืœื™ื˜ ืฉืžื›ื™ื•ื•ืŸ ืฉื”ืกื•ื’ื™ื ืฉื•ื ื™ื, ื™ืฉ ืฆื•ืจืš ืงื•ื“ื ื›ืœ ืœืงื‘ืœ ืืช ื›ื•ืœื ืืช ื”ื ืชื•ื ื™ื ื•ืœืกื ืŸ ืื•ืชื ื‘ืื•ืคืŸ ืžืงื•ืžื™.

ื”ื‘ื” ื ื—ื–ื™ืจ ืืช ืžืกื ืŸ ื”ืชืืจื™ื›ื™ื ืœืขืจื›ื• ื”ืžืงื•ืจื™.

ืคืจื“ื™ ื ื’ื“ Jsonb

ื‘ืื•ืคืŸ ื›ืœืœื™, ืฉื“ื•ืช ื•ืชืืจื™ื›ื™ื ื‘ื•ืœื™ืื ื™ื™ื ื›ื‘ืจ ื”ืื™ืฆื• ืืช ื”ืฉืื™ืœืชื” ืฉืœื ื• ื‘ืžื™ื“ื” ืžืกืคืงืช, ืื‘ืœ ื ื•ืชืจ ืขื•ื“ ืกื•ื’ ื ืชื•ื ื™ื ืื—ื“. ื”ืงืจื‘ ืขื ื”ืกื™ื ื•ืŸ ืœืคื™ื•, ืœืžืขืŸ ื”ืืžืช, ืขื“ื™ื™ืŸ ืœื ื”ืกืชื™ื™ื, ืœืžืจื•ืช ืฉื’ื ื›ืืŸ ื™ืฉ ื”ืฆืœื—ื”. ืื– ื›ืš ื”ืฆืœื—ื ื• ืœื”ืขื‘ื™ืจ ืืช ื”ืžืกื ืŸ ืœื™ื“ื• jsonb ืฉื“ื” ืœืฉืจืช ื”ืžืจื•ื—ืง.

explain analyze verbose
SELECT count(1)
FROM fdw_schema.table 
WHERE is_active is True
AND created_dt BETWEEN CURRENT_DATE - INTERVAL '7 month' 
AND CURRENT_DATE - INTERVAL '6 month'
AND meta @> '{"source":"test"}'::jsonb;

Aggregate  (cost=245463.60..245463.61 rows=1 width=8) (actual time=6727.589..6727.590 rows=1 loops=1)
  Output: count(1)
  ->  Foreign Scan on fdw_schema."table"  (cost=1100.00..245459.90 rows=1478 width=0) (actual time=16.213..6634.794 rows=1360025 loops=1)
        Output: "table".id, "table".is_active, "table".meta, "table".created_dt
        Filter: (("table".is_active IS TRUE) AND ("table".created_dt >= (('now'::cstring)::date - '7 mons'::interval)) AND ("table".created_dt <= ((('now'::cstring)::date)::timestamp with time zone - '6 mons'::interval)))
        Rows Removed by Filter: 619961
        Remote SQL: SELECT created_dt, is_active FROM fdw_schema.table WHERE ((meta @> '{"source": "test"}'::jsonb))
Planning time: 0.747 ms
Execution time: 6727.815 ms

ื‘ืžืงื•ื ืœืกื ืŸ ืื•ืคืจื˜ื•ืจื™ื, ืขืœื™ืš ืœื”ืฉืชืžืฉ ื‘ื ื•ื›ื—ื•ืช ืฉืœ ืื•ืคืจื˜ื•ืจ ืื—ื“ jsonb ื‘ืฉื•ื ื”. 7 ืฉื ื™ื•ืช ื‘ืžืงื•ื 29 ื”ืžืงื•ืจื™ื•ืช. ืขื“ ื›ื” ื–ื• ื”ืืคืฉืจื•ืช ื”ืžื•ืฆืœื—ืช ื”ื™ื—ื™ื“ื” ืœื”ืขื‘ืจืช ืžืกื ื ื™ื ื‘ืืžืฆืขื•ืช jsonb ืœืฉืจืช ืžืจื•ื—ืง, ืื‘ืœ ื›ืืŸ ื—ืฉื•ื‘ ืœืงื—ืช ื‘ื—ืฉื‘ื•ืŸ ืžื’ื‘ืœื” ืื—ืช: ืื ื—ื ื• ืžืฉืชืžืฉื™ื ื‘ื’ืจืกื” 9.6 ืฉืœ ืžืกื“ ื”ื ืชื•ื ื™ื, ืื‘ืœ ืขื“ ืกื•ืฃ ืืคืจื™ืœ ืื ื—ื ื• ืžืชื›ื ื ื™ื ืœื”ืฉืœื™ื ืืช ื”ื‘ื“ื™ืงื•ืช ื”ืื—ืจื•ื ื•ืช ื•ืœืขื‘ื•ืจ ืœื’ืจืกื” 12. ืœืื—ืจ ืฉื ืขื“ื›ืŸ, ื ื›ืชื•ื‘ ืื™ืš ื–ื” ื”ืฉืคื™ืข, ื›ื™ ื™ืฉ ื“ื™ ื”ืจื‘ื” ืฉื™ื ื•ื™ื™ื ืฉื™ืฉ ืœื”ื ื”ืจื‘ื” ืชืงื•ื•ื”: json_path, ื”ืชื ื”ื’ื•ืช ื—ื“ืฉื” ืฉืœ CTE, push down (ืงื™ื™ื ืžืื– ื’ืจืกื” 10). ืื ื™ ืžืžืฉ ืจื•ืฆื” ืœื ืกื•ืช ืืช ื–ื” ื‘ืงืจื•ื‘.

ื’ืžื•ืจ ืื•ืชื•

ื‘ื“ืงื ื• ื›ื™ืฆื“ ื›ืœ ืฉื™ื ื•ื™ ื”ืฉืคื™ืข ืขืœ ืžื”ื™ืจื•ืช ื”ื‘ืงืฉื” ื‘ื ืคืจื“. ื›ืขืช ื ืจืื” ืžื” ืงื•ืจื” ื›ืืฉืจ ื›ืœ ืฉืœื•ืฉืช ื”ืžืกื ื ื™ื ื›ืชื•ื‘ื™ื ื‘ืฆื•ืจื” ื ื›ื•ื ื”.

explain analyze verbose
SELECT count(1)
FROM fdw_schema.table 
WHERE is_active = True
AND created_dt >= (SELECT CURRENT_DATE::timestamptz - INTERVAL '7 month') 
AND created_dt <(SELECT CURRENT_DATE::timestamptz - INTERVAL '6 month')
AND meta @> '{"source":"test"}'::jsonb;

Aggregate  (cost=322041.51..322041.52 rows=1 width=8) (actual time=2278.867..2278.867 rows=1 loops=1)
  Output: count(1)
  InitPlan 1 (returns $0)
    ->  Result  (cost=0.00..0.02 rows=1 width=8) (actual time=0.010..0.010 rows=1 loops=1)
          Output: ((('now'::cstring)::date)::timestamp with time zone - '7 mons'::interval)
  InitPlan 2 (returns $1)
    ->  Result  (cost=0.00..0.02 rows=1 width=8) (actual time=0.003..0.003 rows=1 loops=1)
          Output: ((('now'::cstring)::date)::timestamp with time zone - '6 mons'::interval)
  ->  Foreign Scan on fdw_schema."table"  (cost=100.02..322041.41 rows=25 width=0) (actual time=8.597..2153.809 rows=1360025 loops=1)
        Output: "table".id, "table".is_active, "table".meta, "table".created_dt
        Remote SQL: SELECT NULL FROM fdw_schema.table WHERE (is_active) AND ((created_dt >= $1::timestamp with time zone)) AND ((created_dt < $2::timestamp with time zone)) AND ((meta @> '{"source": "test"}'::jsonb))
Planning time: 0.820 ms
Execution time: 2279.087 ms

ื›ืŸ, ื”ื‘ืงืฉื” ื ืจืื™ืช ืžืกื•ื‘ื›ืช ื™ื•ืชืจ, ืžื“ื•ื‘ืจ ื‘ืชืฉืœื•ื ืžืื•ืœืฅ, ืื‘ืœ ืžื”ื™ืจื•ืช ื”ื‘ื™ืฆื•ืข ื”ื™ื 2 ืฉื ื™ื•ืช, ืฉื–ื” ื™ื•ืชืจ ืžืคื™ 10 ืžื”ืจ ื™ื•ืชืจ! ื•ืื ื—ื ื• ืžื“ื‘ืจื™ื ืขืœ ืฉืื™ืœืชื” ืคืฉื•ื˜ื” ืžื•ืœ ืžืขืจืš ื ืชื•ื ื™ื ืงื˜ืŸ ื™ื—ืกื™ืช. ื‘ื‘ืงืฉื•ืช ืืžื™ืชื™ื•ืช ืงื™ื‘ืœื ื• ืขืœื™ื™ื” ืฉืœ ืขื“ ืคื™ ื›ืžื” ืžืื•ืช.

ืœืกื™ื›ื•ื: ืื ืืชื ืžืฉืชืžืฉื™ื ื‘-PostgreSQL ืขื FDW, ืชืžื™ื“ ืชื‘ื“ืงื• ืฉื›ืœ ื”ืคื™ืœื˜ืจื™ื ื ืฉืœื—ื™ื ืœืฉืจืช ื”ืžืจื•ื—ืง, ื•ืชืฉืžื—ื•... ืœืคื—ื•ืช ืขื“ ืฉืชื’ื™ืขื• ืœื”ืฆื˜ืจืคื•ืช ื‘ื™ืŸ ื˜ื‘ืœืื•ืช ืžืฉืจืชื™ื ืฉื•ื ื™ื. ืื‘ืœ ื–ื” ืกื™ืคื•ืจ ืœืžืืžืจ ืื—ืจ.

ืชื•ื“ื” ืœืš ืขืœ ืชืฉื•ืžืช ื”ืœื‘! ืืฉืžื— ืœืฉืžื•ืข ืฉืืœื•ืช, ื”ืขืจื•ืช ื•ืกื™ืคื•ืจื™ื ืขืœ ื”ื—ื•ื•ื™ื•ืช ืฉืœืš ื‘ืชื’ื•ื‘ื•ืช.

ืžืงื•ืจ: www.habr.com

ื”ื•ืกืคืช ืชื’ื•ื‘ื”