Only consider pseudo constants for shortcuts (#4712)

It seems that we need to consider only pseudo constants while doing some
shortcuts in planning. For example there could be a false clause but it
can contribute to the result in which case it will not be a pseudo
constant.
pull/4713/head^2
SaitTalhaNisanci 2021-02-15 18:39:37 +03:00 committed by GitHub
parent 0f1ce7a913
commit bcbd24f8de
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 237 additions and 76 deletions

View File

@ -93,6 +93,7 @@
#include "distributed/multi_router_planner.h"
#include "distributed/multi_physical_planner.h"
#include "distributed/multi_server_executor.h"
#include "distributed/multi_router_planner.h"
#include "distributed/query_colocation_checker.h"
#include "distributed/query_pushdown_planning.h"
#include "distributed/recursive_planning.h"
@ -395,13 +396,17 @@ HasConstantFilterOnUniqueColumn(RangeTblEntry *rangeTableEntry,
*/
return false;
}
List *baseRestrictionList = relationRestriction->relOptInfo->baserestrictinfo;
List *restrictClauseList = get_all_actual_clauses(baseRestrictionList);
if (ContainsFalseClause(restrictClauseList))
bool joinOnFalse = JoinConditionIsOnFalse(relationRestriction->relOptInfo->joininfo);
if (joinOnFalse)
{
/* If there is a WHERE FALSE, we consider it as a constant filter. */
return true;
}
List *baseRestrictionList = relationRestriction->relOptInfo->baserestrictinfo;
List *restrictClauseList = get_all_actual_clauses(baseRestrictionList);
List *rteEqualityColumnsNos =
FetchEqualityAttrNumsForRTE((Node *) restrictClauseList);

View File

@ -2705,8 +2705,6 @@ TargetShardIntervalsForRestrictInfo(RelationRestrictionContext *restrictionConte
List *baseRestrictionList = relationRestriction->relOptInfo->baserestrictinfo;
List *restrictClauseList = get_all_actual_clauses(baseRestrictionList);
List *prunedShardIntervalList = NIL;
List *joinInfoList = relationRestriction->relOptInfo->joininfo;
List *pseudoRestrictionList = extract_actual_clauses(joinInfoList, true);
/*
* Queries may have contradiction clauses like 'false', or '1=0' in
@ -2714,8 +2712,9 @@ TargetShardIntervalsForRestrictInfo(RelationRestrictionContext *restrictionConte
* inside relOptInfo->joininfo list. We treat such cases as if all
* shards of the table are pruned out.
*/
bool whereFalseQuery = ContainsFalseClause(pseudoRestrictionList);
if (!whereFalseQuery && shardCount > 0)
bool joinFalseQuery = JoinConditionIsOnFalse(
relationRestriction->relOptInfo->joininfo);
if (!joinFalseQuery && shardCount > 0)
{
Const *restrictionPartitionValueConst = NULL;
prunedShardIntervalList = PruneShards(relationId, tableId, restrictClauseList,
@ -2760,6 +2759,22 @@ TargetShardIntervalsForRestrictInfo(RelationRestrictionContext *restrictionConte
}
/*
* JoinConditionIsOnFalse returns true for queries that
* have contradiction clauses like 'false', or '1=0' in
* their filters. Such queries would have pseudo constant 'false'
* inside joininfo list.
*/
bool
JoinConditionIsOnFalse(List *joinInfoList)
{
List *pseudoJoinRestrictionList = extract_actual_clauses(joinInfoList, true);
bool joinFalseQuery = ContainsFalseClause(pseudoJoinRestrictionList);
return joinFalseQuery;
}
/*
* RelationPrunesToMultipleShards returns true if the given list of
* relation-to-shard mappings contains at least two mappings with

View File

@ -18,6 +18,7 @@
#include "distributed/metadata_cache.h"
#include "distributed/multi_logical_planner.h"
#include "distributed/multi_logical_optimizer.h"
#include "distributed/multi_router_planner.h"
#include "distributed/pg_dist_partition.h"
#include "distributed/query_utils.h"
#include "distributed/relation_restriction_equivalence.h"
@ -1859,11 +1860,10 @@ GetRestrictInfoListForRelation(RangeTblEntry *rangeTblEntry,
}
RelOptInfo *relOptInfo = relationRestriction->relOptInfo;
List *joinRestrictInfo = relOptInfo->joininfo;
List *baseRestrictInfo = relOptInfo->baserestrictinfo;
List *joinRestrictClauseList = get_all_actual_clauses(joinRestrictInfo);
if (ContainsFalseClause(joinRestrictClauseList))
bool joinConditionIsOnFalse = JoinConditionIsOnFalse(relOptInfo->joininfo);
if (joinConditionIsOnFalse)
{
/* found WHERE false, no need to continue, we just return a false clause */
bool value = false;

View File

@ -97,6 +97,7 @@ extern void GenerateSingleShardRouterTaskList(Job *job,
extern PlannedStmt * FastPathPlanner(Query *originalQuery, Query *parse, ParamListInfo
boundParams);
extern bool FastPathRouterQuery(Query *query, Node **distributionKeyValue);
extern bool JoinConditionIsOnFalse(List *relOptInfo);
#endif /* MULTI_ROUTER_PLANNER_H */

View File

@ -188,6 +188,12 @@ s/relation with OID [0-9]+ does not exist/relation with OID XXXX does not exist/
# ignore DEBUG1 messages that Postgres generates
/^DEBUG: rehashing catalog cache id [0-9]+$/d
# ignore JIT related messages
/^DEBUG: probing availability of JIT.*/d
/^DEBUG: provider not available, disabling JIT for current session.*/d
# ignore timing statistics for VACUUM VERBOSE
/CPU: user: .*s, system: .*s, elapsed: .*s/d

File diff suppressed because one or more lines are too long

View File

@ -1010,20 +1010,19 @@ UPDATE reference_table SET key = 1 FROM (SELECT * FROM postgres_table) l WHERE l
DEBUG: generating subplan XXX_1 for subquery SELECT key, value, value_2 FROM local_table_join.postgres_table
DEBUG: Plan XXX query after replacing subqueries and CTEs: UPDATE local_table_join.reference_table SET key = 1 FROM (SELECT intermediate_result.key, intermediate_result.value, intermediate_result.value_2 FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text, value_2 jsonb)) l WHERE (l.key OPERATOR(pg_catalog.=) 10)
SELECT count(*) FROM postgres_table JOIN distributed_table USING(key) WHERE FALSE;
DEBUG: Wrapping relation "postgres_table" to a subquery
DEBUG: generating subplan XXX_1 for subquery SELECT key FROM local_table_join.postgres_table WHERE false
DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((SELECT postgres_table_1.key, NULL::text AS value, NULL::jsonb AS value_2 FROM (SELECT intermediate_result.key FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer)) postgres_table_1) postgres_table JOIN local_table_join.distributed_table USING (key)) WHERE false
DEBUG: Wrapping relation "distributed_table" to a subquery
DEBUG: generating subplan XXX_1 for subquery SELECT key FROM local_table_join.distributed_table WHERE false
DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (local_table_join.postgres_table JOIN (SELECT distributed_table_1.key, NULL::text AS value, NULL::jsonb AS value_2 FROM (SELECT intermediate_result.key FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer)) distributed_table_1) distributed_table USING (key)) WHERE false
count
---------------------------------------------------------------------
0
(1 row)
SELECT count(*) FROM (SELECT * FROM distributed_table JOIN postgres_table USING(key) WHERE false) foo JOIN local_partitioned_table USING(key);
DEBUG: Wrapping relation "postgres_table" to a subquery
DEBUG: generating subplan XXX_1 for subquery SELECT key FROM local_table_join.postgres_table WHERE false
DEBUG: Wrapping relation "local_partitioned_table" to a subquery
DEBUG: generating subplan XXX_2 for subquery SELECT key FROM local_table_join.local_partitioned_table WHERE false
DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((SELECT distributed_table.key, distributed_table.value, distributed_table.value_2, postgres_table.value, postgres_table.value_2 FROM (local_table_join.distributed_table JOIN (SELECT postgres_table_1.key, NULL::text AS value, NULL::jsonb AS value_2 FROM (SELECT intermediate_result.key FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer)) postgres_table_1) postgres_table USING (key)) WHERE false) foo(key, value, value_2, value_1, value_2_1) JOIN (SELECT local_partitioned_table_1.key, NULL::text AS value FROM (SELECT intermediate_result.key FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(key integer)) local_partitioned_table_1) local_partitioned_table USING (key))
DEBUG: Wrapping relation "distributed_table" to a subquery
DEBUG: generating subplan XXX_1 for subquery SELECT key FROM local_table_join.distributed_table WHERE false
DEBUG: generating subplan XXX_2 for subquery SELECT distributed_table.key, distributed_table.value, distributed_table.value_2, postgres_table.value, postgres_table.value_2 FROM ((SELECT distributed_table_1.key, NULL::text AS value, NULL::jsonb AS value_2 FROM (SELECT intermediate_result.key FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer)) distributed_table_1) distributed_table JOIN local_table_join.postgres_table USING (key)) WHERE false
DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((SELECT intermediate_result.key, intermediate_result.value, intermediate_result.value_2, intermediate_result.value_1 AS value, intermediate_result.value_2_1 AS value_2 FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text, value_2 jsonb, value_1 text, value_2_1 jsonb)) foo(key, value, value_2, value_1, value_2_1) JOIN local_table_join.local_partitioned_table USING (key))
count
---------------------------------------------------------------------
0
@ -1506,8 +1505,111 @@ where a + b + c > 0;
1
(1 row)
--issue 4706
CREATE TABLE table1(a int);
CREATE TABLE table2(a int);
INSERT INTO table1 VALUES (1);
INSERT INTO table2 VALUES (1);
-- make sure all the followings give the same result as postgres tables.
SELECT 1 AS res FROM table2 RIGHT JOIN (SELECT 1 FROM table1, table2) AS sub1 ON false;
res
---------------------------------------------------------------------
1
(1 row)
SET client_min_messages to DEBUG1;
BEGIN;
SELECT create_distributed_table('table1', 'a');
NOTICE: Copying data from local table...
DEBUG: Copied 1 rows
NOTICE: copying the data has completed
DETAIL: The local data in the table is no longer visible, but is still on disk.
HINT: To remove the local data, run: SELECT truncate_local_data_after_distributing_table($$local_table_join.table1$$)
create_distributed_table
---------------------------------------------------------------------
(1 row)
SELECT 1 AS res FROM table2 RIGHT JOIN (SELECT 1 FROM table1, table2) AS sub1 ON false;
DEBUG: Wrapping relation "table2" to a subquery
DEBUG: generating subplan XXX_1 for subquery SELECT NULL::integer AS "dummy-1" FROM local_table_join.table2 WHERE true
DEBUG: Wrapping relation "table2" to a subquery
DEBUG: generating subplan XXX_2 for subquery SELECT NULL::integer AS "dummy-1" FROM local_table_join.table2 WHERE true
DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT 1 AS res FROM ((SELECT NULL::integer AS a FROM (SELECT intermediate_result."dummy-1" FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result("dummy-1" integer)) table2_1) table2 RIGHT JOIN (SELECT 1 FROM local_table_join.table1, (SELECT NULL::integer AS a FROM (SELECT intermediate_result."dummy-1" FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result("dummy-1" integer)) table2_2) table2_1) sub1("?column?") ON (false))
res
---------------------------------------------------------------------
1
(1 row)
ROLLBACK;
BEGIN;
SELECT create_distributed_table('table2', 'a');
NOTICE: Copying data from local table...
DEBUG: Copied 1 rows
NOTICE: copying the data has completed
DETAIL: The local data in the table is no longer visible, but is still on disk.
HINT: To remove the local data, run: SELECT truncate_local_data_after_distributing_table($$local_table_join.table2$$)
create_distributed_table
---------------------------------------------------------------------
(1 row)
-- currently not supported
SELECT 1 AS res FROM table2 RIGHT JOIN (SELECT 1 FROM table1, table2) AS sub1 ON false;
DEBUG: Wrapping relation "table1" to a subquery
DEBUG: generating subplan XXX_1 for subquery SELECT NULL::integer AS "dummy-1" FROM local_table_join.table1 WHERE true
DEBUG: generating subplan XXX_2 for subquery SELECT 1 FROM (SELECT NULL::integer AS a FROM (SELECT intermediate_result."dummy-1" FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result("dummy-1" integer)) table1_1) table1, local_table_join.table2
DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT 1 AS res FROM (local_table_join.table2 RIGHT JOIN (SELECT intermediate_result."?column?" FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result("?column?" integer)) sub1("?column?") ON (false))
ERROR: cannot pushdown the subquery
DETAIL: Complex subqueries and CTEs cannot be in the outer part of the outer join
ROLLBACK;
BEGIN;
SELECT create_reference_table('table1');
NOTICE: Copying data from local table...
DEBUG: Copied 1 rows
NOTICE: copying the data has completed
DETAIL: The local data in the table is no longer visible, but is still on disk.
HINT: To remove the local data, run: SELECT truncate_local_data_after_distributing_table($$local_table_join.table1$$)
create_reference_table
---------------------------------------------------------------------
(1 row)
SELECT 1 AS res FROM table2 RIGHT JOIN (SELECT 1 FROM table1, table2) AS sub1 ON false;
DEBUG: Wrapping relation "table2" to a subquery
DEBUG: generating subplan XXX_1 for subquery SELECT NULL::integer AS "dummy-1" FROM local_table_join.table2 WHERE true
DEBUG: Wrapping relation "table2" to a subquery
DEBUG: generating subplan XXX_2 for subquery SELECT NULL::integer AS "dummy-1" FROM local_table_join.table2 WHERE true
DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT 1 AS res FROM ((SELECT NULL::integer AS a FROM (SELECT intermediate_result."dummy-1" FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result("dummy-1" integer)) table2_1) table2 RIGHT JOIN (SELECT 1 FROM local_table_join.table1, (SELECT NULL::integer AS a FROM (SELECT intermediate_result."dummy-1" FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result("dummy-1" integer)) table2_2) table2_1) sub1("?column?") ON (false))
res
---------------------------------------------------------------------
1
(1 row)
ROLLBACK;
BEGIN;
SELECT create_reference_table('table2');
NOTICE: Copying data from local table...
DEBUG: Copied 1 rows
NOTICE: copying the data has completed
DETAIL: The local data in the table is no longer visible, but is still on disk.
HINT: To remove the local data, run: SELECT truncate_local_data_after_distributing_table($$local_table_join.table2$$)
create_reference_table
---------------------------------------------------------------------
(1 row)
SELECT 1 AS res FROM table2 RIGHT JOIN (SELECT 1 FROM table1, table2) AS sub1 ON false;
DEBUG: Wrapping relation "table1" to a subquery
DEBUG: generating subplan XXX_1 for subquery SELECT NULL::integer AS "dummy-1" FROM local_table_join.table1 WHERE true
DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT 1 AS res FROM (local_table_join.table2 RIGHT JOIN (SELECT 1 FROM (SELECT NULL::integer AS a FROM (SELECT intermediate_result."dummy-1" FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result("dummy-1" integer)) table1_1) table1, local_table_join.table2 table2_1) sub1("?column?") ON (false))
res
---------------------------------------------------------------------
1
(1 row)
ROLLBACK;
RESET client_min_messages;
\set VERBOSITY terse
DROP SCHEMA local_table_join CASCADE;
NOTICE: drop cascades to 20 other objects
NOTICE: drop cascades to 22 other objects

View File

@ -437,8 +437,40 @@ select COUNT(*) from
inner join tbl1 on (select 1 from custom_pg_type) >= d
left join pg_dist_rebalance_strategy on 'by_shard_count' = name
where a + b + c > 0;
--issue 4706
CREATE TABLE table1(a int);
CREATE TABLE table2(a int);
INSERT INTO table1 VALUES (1);
INSERT INTO table2 VALUES (1);
-- make sure all the followings give the same result as postgres tables.
SELECT 1 AS res FROM table2 RIGHT JOIN (SELECT 1 FROM table1, table2) AS sub1 ON false;
SET client_min_messages to DEBUG1;
BEGIN;
SELECT create_distributed_table('table1', 'a');
SELECT 1 AS res FROM table2 RIGHT JOIN (SELECT 1 FROM table1, table2) AS sub1 ON false;
ROLLBACK;
BEGIN;
SELECT create_distributed_table('table2', 'a');
-- currently not supported
SELECT 1 AS res FROM table2 RIGHT JOIN (SELECT 1 FROM table1, table2) AS sub1 ON false;
ROLLBACK;
BEGIN;
SELECT create_reference_table('table1');
SELECT 1 AS res FROM table2 RIGHT JOIN (SELECT 1 FROM table1, table2) AS sub1 ON false;
ROLLBACK;
BEGIN;
SELECT create_reference_table('table2');
SELECT 1 AS res FROM table2 RIGHT JOIN (SELECT 1 FROM table1, table2) AS sub1 ON false;
ROLLBACK;
RESET client_min_messages;
\set VERBOSITY terse