Skip to content

Files

Latest commit

Dec 15, 2023
f400df2 · Dec 15, 2023

History

History
154 lines (127 loc) · 8 KB

20210801_03.md

File metadata and controls

154 lines (127 loc) · 8 KB

PostgreSQL 15 preview - postgres_fdw 支持case 语句pushdown

作者

digoal

日期

2021-08-01

标签

PostgreSQL , case , postgres_fdw , 下推 , pushdown


背景

https://git.postgresql.org/gitweb/?p=postgresql.git;a=commit;h=5d44fff01eebfe0c7a118326605864e662a44f46

In postgres_fdw, allow CASE expressions to be pushed to the remote server.  
author	Tom Lane <tgl@sss.pgh.pa.us>	  
Fri, 30 Jul 2021 17:39:48 +0000 (13:39 -0400)  
committer	Tom Lane <tgl@sss.pgh.pa.us>	  
Fri, 30 Jul 2021 17:39:48 +0000 (13:39 -0400)  
commit	5d44fff01eebfe0c7a118326605864e662a44f46  
tree	32a3521ca424393c75a7bb57a71f4b38135aefde	tree  
parent	1d919de5eb3fffa7cc9479ed6d2915fb89794459	commit | diff  
In postgres_fdw, allow CASE expressions to be pushed to the remote server.  
  
This is simple enough except for the need to check whether CaseTestExpr  
nodes have a collation that is not derived from a remote Var.  For that,  
examine the CASE's "arg" expression and then pass that info down into the  
recursive examination of the WHEN expressions.  
  
Alexander Pyhalov, reviewed by Gilles Darold and myself  
  
Discussion: https://postgr.es/m/fda09032e90d85d9b726a41e03f9097f@postgrespro.ru  
+-- Test CASE pushdown  
+EXPLAIN (VERBOSE, COSTS OFF)  
+SELECT c1,c2,c3 FROM ft2 WHERE CASE WHEN c1 > 990 THEN c1 END < 1000 ORDER BY c1;  
+                                                                           QUERY PLAN                                                                             
+----------------------------------------------------------------------------------------------------------------------------------------------------------------  
+ Foreign Scan on public.ft2  
+   Output: c1, c2, c3  
+   Remote SQL: SELECT "C 1", c2, c3 FROM "S 1"."T 1" WHERE (((CASE WHEN ("C 1" > 990) THEN "C 1" ELSE NULL::integer END) < 1000)) ORDER BY "C 1" ASC NULLS LAST  
+(3 rows)  
+  
+SELECT c1,c2,c3 FROM ft2 WHERE CASE WHEN c1 > 990 THEN c1 END < 1000 ORDER BY c1;  
+ c1  | c2 |  c3     
+-----+----+-------  
+ 991 |  1 | 00991  
+ 992 |  2 | 00992  
+ 993 |  3 | 00993  
+ 994 |  4 | 00994  
+ 995 |  5 | 00995  
+ 996 |  6 | 00996  
+ 997 |  7 | 00997  
+ 998 |  8 | 00998  
+ 999 |  9 | 00999  
+(9 rows)  
+  
+-- Nested CASE  
+EXPLAIN (VERBOSE, COSTS OFF)  
+SELECT c1,c2,c3 FROM ft2 WHERE CASE CASE WHEN c2 > 0 THEN c2 END WHEN 100 THEN 601 WHEN c2 THEN c2 ELSE 0 END > 600 ORDER BY c1;  
+                                                                                                QUERY PLAN                                                                                                   
+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------  
+ Foreign Scan on public.ft2  
+   Output: c1, c2, c3  
+   Remote SQL: SELECT "C 1", c2, c3 FROM "S 1"."T 1" WHERE (((CASE (CASE WHEN (c2 > 0) THEN c2 ELSE NULL::integer END) WHEN 100 THEN 601 WHEN c2 THEN c2 ELSE 0 END) > 600)) ORDER BY "C 1" ASC NULLS LAST  
+(3 rows)  
+  
+SELECT c1,c2,c3 FROM ft2 WHERE CASE CASE WHEN c2 > 0 THEN c2 END WHEN 100 THEN 601 WHEN c2 THEN c2 ELSE 0 END > 600 ORDER BY c1;  
+ c1 | c2 | c3   
+----+----+----  
+(0 rows)  
+  
+-- CASE arg WHEN  
+EXPLAIN (VERBOSE, COSTS OFF)  
+SELECT * FROM ft1 WHERE c1 > (CASE mod(c1, 4) WHEN 0 THEN 1 WHEN 2 THEN 50 ELSE 100 END);  
+                                                                        QUERY PLAN                                                                          
+----------------------------------------------------------------------------------------------------------------------------------------------------------  
+ Foreign Scan on public.ft1  
+   Output: c1, c2, c3, c4, c5, c6, c7, c8  
+   Remote SQL: SELECT "C 1", c2, c3, c4, c5, c6, c7, c8 FROM "S 1"."T 1" WHERE (("C 1" > (CASE mod("C 1", 4) WHEN 0 THEN 1 WHEN 2 THEN 50 ELSE 100 END)))  
+(3 rows)  
+  
+-- CASE cannot be pushed down because of unshippable arg clause  
+EXPLAIN (VERBOSE, COSTS OFF)  
+SELECT * FROM ft1 WHERE c1 > (CASE random()::integer WHEN 0 THEN 1 WHEN 2 THEN 50 ELSE 100 END);  
+                                       QUERY PLAN                                          
+-----------------------------------------------------------------------------------------  
+ Foreign Scan on public.ft1  
+   Output: c1, c2, c3, c4, c5, c6, c7, c8  
+   Filter: (ft1.c1 > CASE (random())::integer WHEN 0 THEN 1 WHEN 2 THEN 50 ELSE 100 END)  
+   Remote SQL: SELECT "C 1", c2, c3, c4, c5, c6, c7, c8 FROM "S 1"."T 1"  
+(4 rows)  
+  
+-- these are shippable  
+EXPLAIN (VERBOSE, COSTS OFF)  
+SELECT * FROM ft1 WHERE CASE c6 WHEN 'foo' THEN true ELSE c3 < 'bar' END;  
+                                                                    QUERY PLAN                                                                      
+--------------------------------------------------------------------------------------------------------------------------------------------------  
+ Foreign Scan on public.ft1  
+   Output: c1, c2, c3, c4, c5, c6, c7, c8  
+   Remote SQL: SELECT "C 1", c2, c3, c4, c5, c6, c7, c8 FROM "S 1"."T 1" WHERE ((CASE c6 WHEN 'foo'::text THEN true ELSE (c3 < 'bar'::text) END))  
+(3 rows)  
+  
+EXPLAIN (VERBOSE, COSTS OFF)  
+SELECT * FROM ft1 WHERE CASE c3 WHEN c6 THEN true ELSE c3 < 'bar' END;  
+                                                               QUERY PLAN                                                                  
+-----------------------------------------------------------------------------------------------------------------------------------------  
+ Foreign Scan on public.ft1  
+   Output: c1, c2, c3, c4, c5, c6, c7, c8  
+   Remote SQL: SELECT "C 1", c2, c3, c4, c5, c6, c7, c8 FROM "S 1"."T 1" WHERE ((CASE c3 WHEN c6 THEN true ELSE (c3 < 'bar'::text) END))  
+(3 rows)  
+  
+-- but this is not because of collation  
+EXPLAIN (VERBOSE, COSTS OFF)  
+SELECT * FROM ft1 WHERE CASE c3 COLLATE "C" WHEN c6 THEN true ELSE c3 < 'bar' END;  
+                                     QUERY PLAN                                        
+-------------------------------------------------------------------------------------  
+ Foreign Scan on public.ft1  
+   Output: c1, c2, c3, c4, c5, c6, c7, c8  
+   Filter: CASE (ft1.c3)::text WHEN ft1.c6 THEN true ELSE (ft1.c3 < 'bar'::text) END  
+   Remote SQL: SELECT "C 1", c2, c3, c4, c5, c6, c7, c8 FROM "S 1"."T 1"  
+(4 rows)  

您的愿望将传达给PG kernel hacker、数据库厂商等, 帮助提高数据库产品质量和功能, 说不定下一个PG版本就有您提出的功能点. 针对非常好的提议,奖励限量版PG文化衫、纪念品、贴纸、PG热门书籍等,奖品丰富,快来许愿。开不开森.

digoal's wechat