diff --git a/gpcontrib/pgaudit/expected/pgaudit.out b/gpcontrib/pgaudit/expected/pgaudit.out index 59312560491..3378717fe33 100644 --- a/gpcontrib/pgaudit/expected/pgaudit.out +++ b/gpcontrib/pgaudit/expected/pgaudit.out @@ -795,10 +795,9 @@ NOTICE: AUDIT: SESSION,31,2,READ,SELECT,,,explain select 1;, NOTICE: AUDIT: SESSION,31,3,MISC,EXPLAIN,,,explain select 1;, QUERY PLAN ------------------------------------------ - Result (cost=0.00..0.00 rows=1 width=4) - -> Result (cost=0.00..0.00 rows=1 width=1) - Optimizer: Pivotal Optimizer (GPORCA) -(3 rows) + Result (cost=0.00..0.01 rows=1 width=0) + Optimizer: Postgres query optimizer +(2 rows) -- -- Test that looks inside of do blocks log @@ -880,12 +879,11 @@ BEGIN EXECUTE 'DROP table ' || table_name; END $$;", NOTICE: AUDIT: SESSION,36,2,AST_SEL,SELECT,,,{QUERY...}, -NOTICE: AUDIT: SESSION,36,3,READ,SELECT,,,SELECT 'do_table', -NOTICE: AUDIT: SESSION,36,4,AST_SEL,SELECT,,,{QUERY...}, +NOTICE: AUDIT: SESSION,36,3,AST_SEL,SELECT,,,{QUERY...}, NOTICE: Table doesn't have 'DISTRIBUTED BY' clause -- Using column named 'weird name' as the Greenplum Database data distribution key for this table. -NOTICE: AUDIT: SESSION,36,5,DDL,CREATE TABLE,TABLE,public.do_table,"CREATE TABLE do_table (""weird name"" INT)", -NOTICE: AUDIT: SESSION,36,6,AST_SEL,SELECT,,,{QUERY...}, -NOTICE: AUDIT: SESSION,36,7,DDL,DROP TABLE,TABLE,public.do_table,DROP table do_table, +NOTICE: AUDIT: SESSION,36,4,DDL,CREATE TABLE,TABLE,public.do_table,"CREATE TABLE do_table (""weird name"" INT)", +NOTICE: AUDIT: SESSION,36,5,AST_SEL,SELECT,,,{QUERY...}, +NOTICE: AUDIT: SESSION,36,6,DDL,DROP TABLE,TABLE,public.do_table,DROP table do_table, -- -- Generate an error and make sure the stack gets cleared DO $$ @@ -1087,11 +1085,10 @@ NOTICE: AUDIT: SESSION,60,1,AST_SEL,SELECT,,,{QUERY...}{f XXXX public.test {}}, NOTICE: AUDIT: SESSION,60,2,READ,SELECT,,,SELECT test();, NOTICE: AUDIT: SESSION,60,3,FUNCTION,EXECUTE,FUNCTION,public.test,SELECT test();, NOTICE: AUDIT: SESSION,60,4,AST_SEL,SELECT,,,{QUERY...}, -NOTICE: AUDIT: SESSION,60,5,READ,SELECT,,,SELECT 'cur1'::pg_catalog.refcursor, -NOTICE: AUDIT: SESSION,60,6,AST_SEL,SELECT,,,"{QUERY...}{r XXXX public.hoge {id}}", -NOTICE: AUDIT: SESSION,60,6,AST_SEL,SELECT,TABLE,public.hoge,"{QUERY...}{r XXXX public.hoge {id}}", -NOTICE: AUDIT: SESSION,60,7,READ,SELECT,TABLE,public.hoge,select * from hoge, -NOTICE: AUDIT: SESSION,60,8,AST_SEL,SELECT,,,{QUERY...}, +NOTICE: AUDIT: SESSION,60,5,AST_SEL,SELECT,,,"{QUERY...}{r XXXX public.hoge {id}}", +NOTICE: AUDIT: SESSION,60,5,AST_SEL,SELECT,TABLE,public.hoge,"{QUERY...}{r XXXX public.hoge {id}}", +NOTICE: AUDIT: SESSION,60,6,READ,SELECT,TABLE,public.hoge,select * from hoge, +NOTICE: AUDIT: SESSION,60,7,AST_SEL,SELECT,,,{QUERY...}, test ------ @@ -1232,10 +1229,9 @@ NOTICE: AUDIT: SESSION,72,1,AST_SEL,SELECT,,,"{QUERY...}{f XXXX public.get_out_ NOTICE: AUDIT: SESSION,72,2,READ,SELECT,,,SELECT * FROM get_out_args(3);, NOTICE: AUDIT: SESSION,72,3,FUNCTION,EXECUTE,FUNCTION,public.get_out_args,SELECT * FROM get_out_args(3);, NOTICE: AUDIT: SESSION,72,4,AST_SEL,SELECT,,,{QUERY...}, -NOTICE: AUDIT: SESSION,72,5,READ,SELECT,,,SELECT 1, +NOTICE: AUDIT: SESSION,72,5,AST_SEL,SELECT,,,{QUERY...}, NOTICE: AUDIT: SESSION,72,6,AST_SEL,SELECT,,,{QUERY...}, NOTICE: AUDIT: SESSION,72,7,AST_SEL,SELECT,,,{QUERY...}, -NOTICE: AUDIT: SESSION,72,8,AST_SEL,SELECT,,,{QUERY...}, col_o1 | col_o2 --------+-------- 2 | 3 @@ -1273,10 +1269,9 @@ NOTICE: AUDIT: SESSION,74,1,AST_SEL,SELECT,,,"{QUERY...}{f XXXX public.get_tabl NOTICE: AUDIT: SESSION,74,2,READ,SELECT,,,SELECT * FROM get_table(2);, NOTICE: AUDIT: SESSION,74,3,FUNCTION,EXECUTE,FUNCTION,public.get_table,SELECT * FROM get_table(2);, NOTICE: AUDIT: SESSION,74,4,AST_SEL,SELECT,,,{QUERY...}, -NOTICE: AUDIT: SESSION,74,5,READ,SELECT,,,SELECT 1, +NOTICE: AUDIT: SESSION,74,5,AST_SEL,SELECT,,,{QUERY...}, NOTICE: AUDIT: SESSION,74,6,AST_SEL,SELECT,,,{QUERY...}, NOTICE: AUDIT: SESSION,74,7,AST_SEL,SELECT,,,{QUERY...}, -NOTICE: AUDIT: SESSION,74,8,AST_SEL,SELECT,,,{QUERY...}, col_t1 | col_t2 --------+-------- 2 | 3 diff --git a/src/backend/optimizer/plan/planner.c b/src/backend/optimizer/plan/planner.c index 215d43f7b60..134ca1ee4ff 100644 --- a/src/backend/optimizer/plan/planner.c +++ b/src/backend/optimizer/plan/planner.c @@ -157,6 +157,8 @@ static Plan *pushdown_preliminary_limit(Plan *plan, Node *limitCount, int64 coun static Plan *getAnySubplan(Plan *node); static bool isSimplyUpdatableQuery(Query *query); +static bool isQueryForOrca(Query *parse); +static bool query_has_params(Query *parse); /***************************************************************************** @@ -229,11 +231,15 @@ standard_planner(Query *parse, int cursorOptions, ParamListInfo boundParams) * For these reasons, restrict to using ORCA on the master QD processes only. * * PARALLEL RETRIEVE CURSOR is not supported by ORCA yet. + * + * isQueryForOrca() additionally lets us bypass ORCA for queries that it + * cannot usefully optimize, such as trivial constant queries. */ if (optimizer && GP_ROLE_DISPATCH == Gp_role && IS_QUERY_DISPATCHER() && - (cursorOptions & CURSOR_OPT_PARALLEL_RETRIEVE) == 0) + (cursorOptions & CURSOR_OPT_PARALLEL_RETRIEVE) == 0 && + isQueryForOrca(parse)) { if (gp_log_optimization_time) INSTR_TIME_SET_CURRENT(starttime); @@ -5861,3 +5867,53 @@ isSimplyUpdatableQuery(Query *query) } return false; } + +/* + * query_has_params + * Does the query tree reference any parameters? + */ +static bool +query_has_params_walker(Node *node, void *context) +{ + if (node == NULL) + return false; + if (IsA(node, Param)) + return true; + if (IsA(node, Query)) + return query_tree_walker((Query *) node, query_has_params_walker, + context, 0); + return expression_tree_walker(node, query_has_params_walker, context); +} + +static bool +query_has_params(Query *parse) +{ + return query_tree_walker(parse, query_has_params_walker, NULL, 0); +} + +/* + * isQueryForOrca + * Should this query be handed to the ORCA optimizer at all? + * + * ORCA brings no benefit for trivial constant queries such as "SELECT 42": + * they have no range table to distribute across segments, so the Postgres + * planner handles them directly, without the overhead of an ORCA attempt that + * would only fall back to the Postgres planner anyway. + * + * Queries carrying parameters (for example the bodies of SQL/PL functions) are + * still handed to ORCA, preserving its existing handling of them. + * + * Additional rules for bypassing ORCA can be added here. + */ +static bool +isQueryForOrca(Query *parse) +{ + if (parse->commandType == CMD_SELECT && + parse->rtable == NIL && + !parse->hasSubLinks && + parse->parentStmtType == PARENTSTMTTYPE_NONE && + !query_has_params(parse)) + return false; + + return true; +} diff --git a/src/test/regress/expected/bfv_catalog_optimizer.out b/src/test/regress/expected/bfv_catalog_optimizer.out index cc171e042d4..e24f225b7f9 100644 --- a/src/test/regress/expected/bfv_catalog_optimizer.out +++ b/src/test/regress/expected/bfv_catalog_optimizer.out @@ -257,22 +257,18 @@ reset optimizer_enable_indexscan; create table mpp_bfv_2(a int, b text, primary key (a)) distributed by (a); -- stop falling back to planner when catalog functions are encountered explain select pg_column_size('mpp_bfv_2'); - QUERY PLAN ------------------------------------------------- - Result (cost=0.00..0.00 rows=1 width=4) - -> Result (cost=0.00..0.00 rows=1 width=1) - Settings: optimizer=on - Optimizer status: Pivotal Optimizer (GPORCA) version 2.23.0 -(4 rows) + QUERY PLAN +------------------------------------------ + Result (cost=0.00..0.01 rows=1 width=0) + Optimizer: Postgres query optimizer +(2 rows) explain select pg_lock_status(); - QUERY PLAN ------------------------------------------------- - Result (cost=0.00..0.00 rows=1 width=8) - -> Result (cost=0.00..0.00 rows=1 width=1) - Settings: optimizer=on - Optimizer status: Pivotal Optimizer (GPORCA) version 2.23.0 -(4 rows) + QUERY PLAN +-------------------------------------------- + Result (cost=0.00..5.01 rows=334 width=0) + Optimizer: Postgres query optimizer +(2 rows) select pg_get_constraintdef(pg_constraint.oid) from pg_constraint, pg_class where conrelid=pg_class.oid and pg_class.relname='mpp_bfv_2'; pg_get_constraintdef diff --git a/src/test/regress/output/qp_gist_indexes2_optimizer.source b/src/test/regress/output/qp_gist_indexes2_optimizer.source index bd860b62f48..ab72d9d1cb5 100644 --- a/src/test/regress/output/qp_gist_indexes2_optimizer.source +++ b/src/test/regress/output/qp_gist_indexes2_optimizer.source @@ -413,8 +413,6 @@ DETAIL: No plan has been computed for required properties SELECT count_index_scans('EXPLAIN SELECT owner, property FROM GistTable1 WHERE property IS NULL ORDER BY id;'); INFO: GPORCA failed to produce a plan, falling back to planner -DETAIL: Feature not supported: SIRV functions -INFO: GPORCA failed to produce a plan, falling back to planner DETAIL: No plan has been computed for required properties CONTEXT: SQL statement "EXPLAIN SELECT owner, property FROM GistTable1 WHERE property IS NULL ORDER BY id;" PL/Python function "count_index_scans" @@ -460,8 +458,6 @@ DETAIL: No plan has been computed for required properties SELECT count_index_scans('EXPLAIN SELECT id, property FROM GistTable1 WHERE property IS NULL ORDER BY id;'); INFO: GPORCA failed to produce a plan, falling back to planner -DETAIL: Feature not supported: SIRV functions -INFO: GPORCA failed to produce a plan, falling back to planner DETAIL: No plan has been computed for required properties CONTEXT: SQL statement "EXPLAIN SELECT id, property FROM GistTable1 WHERE property IS NULL ORDER BY id;" PL/Python function "count_index_scans"