mirror of https://github.com/citusdata/citus.git
Correct planner and add more tests
parent
7550b8ad52
commit
b0efffae1c
|
@ -546,7 +546,8 @@ DeferErrorIfUnsupportedSubqueryPushdown(Query *originalQuery,
|
||||||
{
|
{
|
||||||
return DeferredError(ERRCODE_FEATURE_NOT_SUPPORTED,
|
return DeferredError(ERRCODE_FEATURE_NOT_SUPPORTED,
|
||||||
"cannot pushdown the subquery",
|
"cannot pushdown the subquery",
|
||||||
"There exist a reference table in the outer part of the outer join",
|
"There exist a reference table in the outer part of the "
|
||||||
|
"outer join",
|
||||||
NULL);
|
NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1426,18 +1427,19 @@ MultiPlanTree(Query *queryTree)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* HasUnsupportedReferenceTableJoin returns true if there exists a outer join
|
* HasUnsupportedReferenceTableJoin returns true if there exists a outer join
|
||||||
* exist between reference table and distributed tables which does not obey the
|
* between reference table and distributed tables which does not follow
|
||||||
* rules :
|
* the rules :
|
||||||
* - Reference tables can not be located in the outer part of the semi join (or
|
* - Reference tables can not be located in the outer part of the semi join or the
|
||||||
* the inner part of the anti join). Otherwise, we may have duplicate results.
|
* anti join. Otherwise, we may have duplicate results. Although getting duplicate
|
||||||
* Although getting duplicate results is not possible by checking the equality
|
* results is not possible by checking the equality on the column of the reference
|
||||||
* on the column of the reference table and partition column of distributed table,
|
* table and partition column of distributed table, we still keep these checks.
|
||||||
* we still keep these checks. Because, using the reference table in the outer
|
* Because, using the reference table in the outer part of the semi join or anti
|
||||||
* part of the semi join is not very common.
|
* join is not very common.
|
||||||
* - Reference tables can not be located in the outer part of the left join and
|
* - Reference tables can not be located in the outer part of the left join
|
||||||
* inner part of the right join. Otherwise we will definitely have duplicate rows.
|
* (Note that PostgreSQL converts right joins to left joins. While converting
|
||||||
* Beside, reference tables can not be used with full outer joins because of the
|
* join types, innerrel and outerrel are also switched.) Otherwise we will
|
||||||
* same reason.
|
* definitely have duplicate rows. Beside, reference tables can not be used
|
||||||
|
* with full outer joins because of the same reason.
|
||||||
*/
|
*/
|
||||||
static bool
|
static bool
|
||||||
HasUnsupportedReferenceTableJoin(PlannerRestrictionContext *plannerRestrictionContext)
|
HasUnsupportedReferenceTableJoin(PlannerRestrictionContext *plannerRestrictionContext)
|
||||||
|
@ -1455,59 +1457,21 @@ HasUnsupportedReferenceTableJoin(PlannerRestrictionContext *plannerRestrictionCo
|
||||||
RelOptInfo *innerrel = joinRestriction->innerrel;
|
RelOptInfo *innerrel = joinRestriction->innerrel;
|
||||||
RelOptInfo *outerrel = joinRestriction->outerrel;
|
RelOptInfo *outerrel = joinRestriction->outerrel;
|
||||||
|
|
||||||
switch (joinType)
|
if (joinType == JOIN_SEMI || joinType == JOIN_ANTI || joinType == JOIN_LEFT)
|
||||||
{
|
|
||||||
case JOIN_SEMI:
|
|
||||||
{
|
{
|
||||||
if (RelationInfoHasReferenceTable(plannerInfo, outerrel))
|
if (RelationInfoHasReferenceTable(plannerInfo, outerrel))
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
else if (joinType == JOIN_FULL)
|
||||||
|
|
||||||
case JOIN_ANTI:
|
|
||||||
{
|
|
||||||
if (RelationInfoHasReferenceTable(plannerInfo, innerrel))
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case JOIN_LEFT:
|
|
||||||
{
|
|
||||||
if (RelationInfoHasReferenceTable(plannerInfo, outerrel))
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case JOIN_RIGHT:
|
|
||||||
{
|
|
||||||
if (RelationInfoHasReferenceTable(plannerInfo, innerrel))
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case JOIN_FULL:
|
|
||||||
{
|
{
|
||||||
if (RelationInfoHasReferenceTable(plannerInfo, innerrel) ||
|
if (RelationInfoHasReferenceTable(plannerInfo, innerrel) ||
|
||||||
RelationInfoHasReferenceTable(
|
RelationInfoHasReferenceTable(plannerInfo, outerrel))
|
||||||
plannerInfo, outerrel))
|
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
{ }
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
|
@ -1515,7 +1479,7 @@ HasUnsupportedReferenceTableJoin(PlannerRestrictionContext *plannerRestrictionCo
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* ReferenceTableExist check whether the relationInfo has reference table.
|
* RelationInfoHasReferenceTable check whether the relationInfo has reference table.
|
||||||
* Since relation ids of relationInfo indexes to the range table entry list of
|
* Since relation ids of relationInfo indexes to the range table entry list of
|
||||||
* planner info, planner info is also passed.
|
* planner info, planner info is also passed.
|
||||||
*/
|
*/
|
||||||
|
@ -1549,7 +1513,7 @@ HasReferenceTable(Node *node)
|
||||||
{
|
{
|
||||||
List *relationList = NIL;
|
List *relationList = NIL;
|
||||||
ListCell *relationCell = NULL;
|
ListCell *relationCell = NULL;
|
||||||
ExtractRangeTableRelationWalkerInRTE(node, &relationList);
|
ExtractRangeTableRelationWalkerWithRTEExpand(node, &relationList);
|
||||||
|
|
||||||
foreach(relationCell, relationList)
|
foreach(relationCell, relationList)
|
||||||
{
|
{
|
||||||
|
@ -2933,13 +2897,13 @@ ExtractRangeTableRelationWalker(Node *node, List **rangeTableRelationList)
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* ExtractRangeTableRelationWalkerInRTE obtains the list of relations from the
|
* ExtractRangeTableRelationWalkerWithRTEExpand obtains the list of relations
|
||||||
* given node. Note that the difference between this function and
|
* from the given node. Note that the difference between this function and
|
||||||
* ExtractRangeTableRelationWalker is that this one recursively
|
* ExtractRangeTableRelationWalker is that this one recursively
|
||||||
* walk into range table entries if it can.
|
* walk into range table entries if it can.
|
||||||
*/
|
*/
|
||||||
bool
|
bool
|
||||||
ExtractRangeTableRelationWalkerInRTE(Node *node, List **rangeTableRelationList)
|
ExtractRangeTableRelationWalkerWithRTEExpand(Node *node, List **rangeTableRelationList)
|
||||||
{
|
{
|
||||||
bool walkIsComplete = false;
|
bool walkIsComplete = false;
|
||||||
|
|
||||||
|
@ -2950,8 +2914,7 @@ ExtractRangeTableRelationWalkerInRTE(Node *node, List **rangeTableRelationList)
|
||||||
else if (IsA(node, RangeTblEntry))
|
else if (IsA(node, RangeTblEntry))
|
||||||
{
|
{
|
||||||
RangeTblEntry *rangeTableEntry = (RangeTblEntry *) node;
|
RangeTblEntry *rangeTableEntry = (RangeTblEntry *) node;
|
||||||
List *rangeTableList = NIL;
|
List *rangeTableList = list_make1(rangeTableEntry);
|
||||||
rangeTableList = lappend(rangeTableList, rangeTableEntry);
|
|
||||||
|
|
||||||
if (rangeTableEntry->rtekind == RTE_RELATION)
|
if (rangeTableEntry->rtekind == RTE_RELATION)
|
||||||
{
|
{
|
||||||
|
@ -2960,7 +2923,7 @@ ExtractRangeTableRelationWalkerInRTE(Node *node, List **rangeTableRelationList)
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
walkIsComplete = range_table_walker(rangeTableList,
|
walkIsComplete = range_table_walker(rangeTableList,
|
||||||
ExtractRangeTableRelationWalkerInRTE,
|
ExtractRangeTableRelationWalkerWithRTEExpand,
|
||||||
rangeTableRelationList, 0);
|
rangeTableRelationList, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2111,7 +2111,7 @@ ErrorIfUnsupportedShardDistribution(Query *query)
|
||||||
{
|
{
|
||||||
Oid firstTableRelationId = InvalidOid;
|
Oid firstTableRelationId = InvalidOid;
|
||||||
List *relationIdList = RelationIdList(query);
|
List *relationIdList = RelationIdList(query);
|
||||||
List *distributedRelationIdList = NIL;
|
List *nonReferenceRelations = NIL;
|
||||||
ListCell *relationIdCell = NULL;
|
ListCell *relationIdCell = NULL;
|
||||||
uint32 relationIndex = 0;
|
uint32 relationIndex = 0;
|
||||||
uint32 rangeDistributedRelationCount = 0;
|
uint32 rangeDistributedRelationCount = 0;
|
||||||
|
@ -2121,17 +2121,16 @@ ErrorIfUnsupportedShardDistribution(Query *query)
|
||||||
{
|
{
|
||||||
Oid relationId = lfirst_oid(relationIdCell);
|
Oid relationId = lfirst_oid(relationIdCell);
|
||||||
char partitionMethod = PartitionMethod(relationId);
|
char partitionMethod = PartitionMethod(relationId);
|
||||||
|
|
||||||
if (partitionMethod == DISTRIBUTE_BY_RANGE)
|
if (partitionMethod == DISTRIBUTE_BY_RANGE)
|
||||||
{
|
{
|
||||||
rangeDistributedRelationCount++;
|
rangeDistributedRelationCount++;
|
||||||
distributedRelationIdList = lappend_oid(distributedRelationIdList,
|
nonReferenceRelations = lappend_oid(nonReferenceRelations,
|
||||||
relationId);
|
relationId);
|
||||||
}
|
}
|
||||||
else if (partitionMethod == DISTRIBUTE_BY_HASH)
|
else if (partitionMethod == DISTRIBUTE_BY_HASH)
|
||||||
{
|
{
|
||||||
hashDistributedRelationCount++;
|
hashDistributedRelationCount++;
|
||||||
distributedRelationIdList = lappend_oid(distributedRelationIdList,
|
nonReferenceRelations = lappend_oid(nonReferenceRelations,
|
||||||
relationId);
|
relationId);
|
||||||
}
|
}
|
||||||
else if (partitionMethod == DISTRIBUTE_BY_NONE)
|
else if (partitionMethod == DISTRIBUTE_BY_NONE)
|
||||||
|
@ -2156,7 +2155,7 @@ ErrorIfUnsupportedShardDistribution(Query *query)
|
||||||
"partitioned relations are unsupported")));
|
"partitioned relations are unsupported")));
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach(relationIdCell, distributedRelationIdList)
|
foreach(relationIdCell, nonReferenceRelations)
|
||||||
{
|
{
|
||||||
Oid relationId = lfirst_oid(relationIdCell);
|
Oid relationId = lfirst_oid(relationIdCell);
|
||||||
bool coPartitionedTables = false;
|
bool coPartitionedTables = false;
|
||||||
|
|
|
@ -124,7 +124,8 @@ static Index RelationRestrictionPartitionKeyIndex(RelationRestriction *
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* SafeToPushdownUnionSubquery returns true if all the relations are returns
|
* SafeToPushdownUnionSubquery returns true if all the relations are returns
|
||||||
* partition keys in the same ordinal position.
|
* partition keys in the same ordinal position and there is no reference table
|
||||||
|
* exists.
|
||||||
*
|
*
|
||||||
* Note that the function expects (and asserts) the input query to be a top
|
* Note that the function expects (and asserts) the input query to be a top
|
||||||
* level union query defined by TopLevelUnionQuery().
|
* level union query defined by TopLevelUnionQuery().
|
||||||
|
|
|
@ -206,7 +206,8 @@ extern List * TableEntryList(List *rangeTableList);
|
||||||
extern List * UsedTableEntryList(Query *query);
|
extern List * UsedTableEntryList(Query *query);
|
||||||
extern bool ExtractRangeTableRelationWalker(Node *node, List **rangeTableList);
|
extern bool ExtractRangeTableRelationWalker(Node *node, List **rangeTableList);
|
||||||
extern bool ExtractRangeTableEntryWalker(Node *node, List **rangeTableList);
|
extern bool ExtractRangeTableEntryWalker(Node *node, List **rangeTableList);
|
||||||
extern bool ExtractRangeTableRelationWalkerInRTE(Node *node, List **rangeTableList);
|
extern bool ExtractRangeTableRelationWalkerWithRTEExpand(Node *node,
|
||||||
|
List **rangeTableList);
|
||||||
extern List * pull_var_clause_default(Node *node);
|
extern List * pull_var_clause_default(Node *node);
|
||||||
extern bool OperatorImplementsEquality(Oid opno);
|
extern bool OperatorImplementsEquality(Oid opno);
|
||||||
|
|
||||||
|
|
|
@ -446,14 +446,15 @@ Aggregate
|
||||||
Node: host=localhost port=57637 dbname=regression
|
Node: host=localhost port=57637 dbname=regression
|
||||||
-> Aggregate
|
-> Aggregate
|
||||||
-> GroupAggregate
|
-> GroupAggregate
|
||||||
Group Key: (((NULL::user_composite_type)).tenant_id), (((NULL::user_composite_type)).user_id)
|
Group Key: ((users.composite_id).tenant_id), ((users.composite_id).user_id)
|
||||||
-> Sort
|
-> Sort
|
||||||
Sort Key: (((NULL::user_composite_type)).tenant_id), (((NULL::user_composite_type)).user_id)
|
Sort Key: ((users.composite_id).tenant_id), ((users.composite_id).user_id)
|
||||||
-> Nested Loop
|
-> Hash Join
|
||||||
Join Filter: ((NULL::user_composite_type) = events.composite_id)
|
Hash Cond: (users.composite_id = events.composite_id)
|
||||||
-> Result
|
-> Seq Scan on users_1400029 users
|
||||||
One-Time Filter: false
|
Filter: ((composite_id >= '(1,-9223372036854775808)'::user_composite_type) AND (composite_id <= '(1,9223372036854775807)'::user_composite_type))
|
||||||
-> Seq Scan on events_1400027 events
|
-> Hash
|
||||||
|
-> Seq Scan on events_1400025 events
|
||||||
Filter: ((event_type)::text = ANY ('{click,submit,pay}'::text[]))
|
Filter: ((event_type)::text = ANY ('{click,submit,pay}'::text[]))
|
||||||
-- Union and left join subquery pushdown
|
-- Union and left join subquery pushdown
|
||||||
EXPLAIN (COSTS OFF)
|
EXPLAIN (COSTS OFF)
|
||||||
|
@ -531,33 +532,34 @@ HashAggregate
|
||||||
Sort Key: subquery_top.hasdone
|
Sort Key: subquery_top.hasdone
|
||||||
-> Subquery Scan on subquery_top
|
-> Subquery Scan on subquery_top
|
||||||
-> GroupAggregate
|
-> GroupAggregate
|
||||||
Group Key: (((NULL::user_composite_type)).tenant_id), (((NULL::user_composite_type)).user_id), subquery_2.hasdone
|
Group Key: ((users.composite_id).tenant_id), ((users.composite_id).user_id), subquery_2.hasdone
|
||||||
-> Sort
|
-> Sort
|
||||||
Sort Key: (((NULL::user_composite_type)).tenant_id), (((NULL::user_composite_type)).user_id), subquery_2.hasdone
|
Sort Key: ((users.composite_id).tenant_id), ((users.composite_id).user_id), subquery_2.hasdone
|
||||||
-> Hash Left Join
|
-> Hash Left Join
|
||||||
Hash Cond: ((NULL::user_composite_type) = subquery_2.composite_id)
|
Hash Cond: (users.composite_id = subquery_2.composite_id)
|
||||||
-> Unique
|
-> HashAggregate
|
||||||
-> Sort
|
Group Key: ((users.composite_id).tenant_id), ((users.composite_id).user_id), users.composite_id, ('action=>1'::text), events.event_time
|
||||||
Sort Key: (((NULL::user_composite_type)).tenant_id), (((NULL::user_composite_type)).user_id), (NULL::user_composite_type), ('action=>1'::text), events.event_time
|
|
||||||
-> Append
|
-> Append
|
||||||
-> Nested Loop
|
-> Hash Join
|
||||||
Join Filter: ((NULL::user_composite_type) = events.composite_id)
|
Hash Cond: (users.composite_id = events.composite_id)
|
||||||
-> Result
|
-> Seq Scan on users_1400029 users
|
||||||
One-Time Filter: false
|
Filter: ((composite_id >= '(1,-9223372036854775808)'::user_composite_type) AND (composite_id <= '(1,9223372036854775807)'::user_composite_type))
|
||||||
-> Seq Scan on events_1400027 events
|
-> Hash
|
||||||
|
-> Seq Scan on events_1400025 events
|
||||||
Filter: ((event_type)::text = 'click'::text)
|
Filter: ((event_type)::text = 'click'::text)
|
||||||
-> Nested Loop
|
-> Hash Join
|
||||||
Join Filter: ((NULL::user_composite_type) = events_1.composite_id)
|
Hash Cond: (users_1.composite_id = events_1.composite_id)
|
||||||
-> Result
|
-> Seq Scan on users_1400029 users_1
|
||||||
One-Time Filter: false
|
Filter: ((composite_id >= '(1,-9223372036854775808)'::user_composite_type) AND (composite_id <= '(1,9223372036854775807)'::user_composite_type))
|
||||||
-> Seq Scan on events_1400027 events_1
|
-> Hash
|
||||||
|
-> Seq Scan on events_1400025 events_1
|
||||||
Filter: ((event_type)::text = 'submit'::text)
|
Filter: ((event_type)::text = 'submit'::text)
|
||||||
-> Hash
|
-> Hash
|
||||||
-> Subquery Scan on subquery_2
|
-> Subquery Scan on subquery_2
|
||||||
-> Unique
|
-> Unique
|
||||||
-> Sort
|
-> Sort
|
||||||
Sort Key: ((events_2.composite_id).tenant_id), ((events_2.composite_id).user_id)
|
Sort Key: ((events_2.composite_id).tenant_id), ((events_2.composite_id).user_id)
|
||||||
-> Seq Scan on events_1400027 events_2
|
-> Seq Scan on events_1400025 events_2
|
||||||
Filter: ((composite_id >= '(1,-9223372036854775808)'::user_composite_type) AND (composite_id <= '(1,9223372036854775807)'::user_composite_type) AND ((event_type)::text = 'pay'::text))
|
Filter: ((composite_id >= '(1,-9223372036854775808)'::user_composite_type) AND (composite_id <= '(1,9223372036854775807)'::user_composite_type) AND ((event_type)::text = 'pay'::text))
|
||||||
-- Union, left join and having subquery pushdown
|
-- Union, left join and having subquery pushdown
|
||||||
EXPLAIN (COSTS OFF)
|
EXPLAIN (COSTS OFF)
|
||||||
|
@ -703,13 +705,12 @@ Limit
|
||||||
-> Limit
|
-> Limit
|
||||||
-> Sort
|
-> Sort
|
||||||
Sort Key: users.lastseen DESC
|
Sort Key: users.lastseen DESC
|
||||||
-> Subquery Scan on users
|
-> Seq Scan on users_1400029 users
|
||||||
-> Result
|
Filter: ((composite_id >= '(1,-9223372036854775808)'::user_composite_type) AND (composite_id <= '(1,9223372036854775807)'::user_composite_type))
|
||||||
One-Time Filter: false
|
|
||||||
-> Limit
|
-> Limit
|
||||||
-> Sort
|
-> Sort
|
||||||
Sort Key: events.event_time DESC
|
Sort Key: events.event_time DESC
|
||||||
-> Seq Scan on events_1400027 events
|
-> Seq Scan on events_1400025 events
|
||||||
Filter: (composite_id = users.composite_id)
|
Filter: (composite_id = users.composite_id)
|
||||||
-- Test all tasks output
|
-- Test all tasks output
|
||||||
SET citus.explain_all_tasks TO on;
|
SET citus.explain_all_tasks TO on;
|
||||||
|
|
|
@ -446,14 +446,15 @@ Aggregate
|
||||||
Node: host=localhost port=57637 dbname=regression
|
Node: host=localhost port=57637 dbname=regression
|
||||||
-> Aggregate
|
-> Aggregate
|
||||||
-> GroupAggregate
|
-> GroupAggregate
|
||||||
Group Key: (((NULL::user_composite_type)).tenant_id), (((NULL::user_composite_type)).user_id)
|
Group Key: ((users.composite_id).tenant_id), ((users.composite_id).user_id)
|
||||||
-> Sort
|
-> Sort
|
||||||
Sort Key: (((NULL::user_composite_type)).tenant_id), (((NULL::user_composite_type)).user_id)
|
Sort Key: ((users.composite_id).tenant_id), ((users.composite_id).user_id)
|
||||||
-> Nested Loop
|
-> Hash Join
|
||||||
Join Filter: ((NULL::user_composite_type) = events.composite_id)
|
Hash Cond: (users.composite_id = events.composite_id)
|
||||||
-> Result
|
-> Seq Scan on users_1400029 users
|
||||||
One-Time Filter: false
|
Filter: ((composite_id >= '(1,-9223372036854775808)'::user_composite_type) AND (composite_id <= '(1,9223372036854775807)'::user_composite_type))
|
||||||
-> Seq Scan on events_1400027 events
|
-> Hash
|
||||||
|
-> Seq Scan on events_1400025 events
|
||||||
Filter: ((event_type)::text = ANY ('{click,submit,pay}'::text[]))
|
Filter: ((event_type)::text = ANY ('{click,submit,pay}'::text[]))
|
||||||
-- Union and left join subquery pushdown
|
-- Union and left join subquery pushdown
|
||||||
EXPLAIN (COSTS OFF)
|
EXPLAIN (COSTS OFF)
|
||||||
|
@ -531,33 +532,34 @@ HashAggregate
|
||||||
Sort Key: subquery_top.hasdone
|
Sort Key: subquery_top.hasdone
|
||||||
-> Subquery Scan on subquery_top
|
-> Subquery Scan on subquery_top
|
||||||
-> GroupAggregate
|
-> GroupAggregate
|
||||||
Group Key: (((NULL::user_composite_type)).tenant_id), (((NULL::user_composite_type)).user_id), subquery_2.hasdone
|
Group Key: ((users.composite_id).tenant_id), ((users.composite_id).user_id), subquery_2.hasdone
|
||||||
-> Sort
|
-> Sort
|
||||||
Sort Key: (((NULL::user_composite_type)).tenant_id), (((NULL::user_composite_type)).user_id), subquery_2.hasdone
|
Sort Key: ((users.composite_id).tenant_id), ((users.composite_id).user_id), subquery_2.hasdone
|
||||||
-> Hash Left Join
|
-> Hash Left Join
|
||||||
Hash Cond: ((NULL::user_composite_type) = subquery_2.composite_id)
|
Hash Cond: (users.composite_id = subquery_2.composite_id)
|
||||||
-> Unique
|
-> HashAggregate
|
||||||
-> Sort
|
Group Key: ((users.composite_id).tenant_id), ((users.composite_id).user_id), users.composite_id, ('action=>1'::text), events.event_time
|
||||||
Sort Key: (((NULL::user_composite_type)).tenant_id), (((NULL::user_composite_type)).user_id), (NULL::user_composite_type), ('action=>1'::text), events.event_time
|
|
||||||
-> Append
|
-> Append
|
||||||
-> Nested Loop
|
-> Hash Join
|
||||||
Join Filter: ((NULL::user_composite_type) = events.composite_id)
|
Hash Cond: (users.composite_id = events.composite_id)
|
||||||
-> Result
|
-> Seq Scan on users_1400029 users
|
||||||
One-Time Filter: false
|
Filter: ((composite_id >= '(1,-9223372036854775808)'::user_composite_type) AND (composite_id <= '(1,9223372036854775807)'::user_composite_type))
|
||||||
-> Seq Scan on events_1400027 events
|
-> Hash
|
||||||
|
-> Seq Scan on events_1400025 events
|
||||||
Filter: ((event_type)::text = 'click'::text)
|
Filter: ((event_type)::text = 'click'::text)
|
||||||
-> Nested Loop
|
-> Hash Join
|
||||||
Join Filter: ((NULL::user_composite_type) = events_1.composite_id)
|
Hash Cond: (users_1.composite_id = events_1.composite_id)
|
||||||
-> Result
|
-> Seq Scan on users_1400029 users_1
|
||||||
One-Time Filter: false
|
Filter: ((composite_id >= '(1,-9223372036854775808)'::user_composite_type) AND (composite_id <= '(1,9223372036854775807)'::user_composite_type))
|
||||||
-> Seq Scan on events_1400027 events_1
|
-> Hash
|
||||||
|
-> Seq Scan on events_1400025 events_1
|
||||||
Filter: ((event_type)::text = 'submit'::text)
|
Filter: ((event_type)::text = 'submit'::text)
|
||||||
-> Hash
|
-> Hash
|
||||||
-> Subquery Scan on subquery_2
|
-> Subquery Scan on subquery_2
|
||||||
-> Unique
|
-> Unique
|
||||||
-> Sort
|
-> Sort
|
||||||
Sort Key: ((events_2.composite_id).tenant_id), ((events_2.composite_id).user_id)
|
Sort Key: ((events_2.composite_id).tenant_id), ((events_2.composite_id).user_id)
|
||||||
-> Seq Scan on events_1400027 events_2
|
-> Seq Scan on events_1400025 events_2
|
||||||
Filter: ((composite_id >= '(1,-9223372036854775808)'::user_composite_type) AND (composite_id <= '(1,9223372036854775807)'::user_composite_type) AND ((event_type)::text = 'pay'::text))
|
Filter: ((composite_id >= '(1,-9223372036854775808)'::user_composite_type) AND (composite_id <= '(1,9223372036854775807)'::user_composite_type) AND ((event_type)::text = 'pay'::text))
|
||||||
-- Union, left join and having subquery pushdown
|
-- Union, left join and having subquery pushdown
|
||||||
EXPLAIN (COSTS OFF)
|
EXPLAIN (COSTS OFF)
|
||||||
|
@ -703,13 +705,12 @@ Limit
|
||||||
-> Limit
|
-> Limit
|
||||||
-> Sort
|
-> Sort
|
||||||
Sort Key: users.lastseen DESC
|
Sort Key: users.lastseen DESC
|
||||||
-> Subquery Scan on users
|
-> Seq Scan on users_1400029 users
|
||||||
-> Result
|
Filter: ((composite_id >= '(1,-9223372036854775808)'::user_composite_type) AND (composite_id <= '(1,9223372036854775807)'::user_composite_type))
|
||||||
One-Time Filter: false
|
|
||||||
-> Limit
|
-> Limit
|
||||||
-> Sort
|
-> Sort
|
||||||
Sort Key: events.event_time DESC
|
Sort Key: events.event_time DESC
|
||||||
-> Seq Scan on events_1400027 events
|
-> Seq Scan on events_1400025 events
|
||||||
Filter: (composite_id = users.composite_id)
|
Filter: (composite_id = users.composite_id)
|
||||||
-- Test all tasks output
|
-- Test all tasks output
|
||||||
SET citus.explain_all_tasks TO on;
|
SET citus.explain_all_tasks TO on;
|
||||||
|
|
|
@ -1122,8 +1122,7 @@ WHERE
|
||||||
colocated_table_test.value_1 = reference_table_test.value_1;
|
colocated_table_test.value_1 = reference_table_test.value_1;
|
||||||
DEBUG: only reference tables may be queried when targeting a reference table with distributed INSERT ... SELECT
|
DEBUG: only reference tables may be queried when targeting a reference table with distributed INSERT ... SELECT
|
||||||
DEBUG: Collecting INSERT ... SELECT results on coordinator
|
DEBUG: Collecting INSERT ... SELECT results on coordinator
|
||||||
-- now, insert into the hash partitioned table and use reference
|
-- not pushable due to lack of equality between partition column and column of reference table
|
||||||
-- tables in the SELECT queries
|
|
||||||
INSERT INTO
|
INSERT INTO
|
||||||
colocated_table_test (value_1, value_2)
|
colocated_table_test (value_1, value_2)
|
||||||
SELECT
|
SELECT
|
||||||
|
|
|
@ -8,22 +8,112 @@
|
||||||
ALTER SEQUENCE pg_catalog.pg_dist_jobid_seq RESTART 1400000;
|
ALTER SEQUENCE pg_catalog.pg_dist_jobid_seq RESTART 1400000;
|
||||||
|
|
||||||
SET citus.enable_router_execution TO FALSE;
|
SET citus.enable_router_execution TO FALSE;
|
||||||
CREATE TABLE events_reference_table as SELECT * FROM events_table;
|
CREATE TABLE user_buy_test_table(user_id int, item_id int, buy_count int);
|
||||||
CREATE TABLE users_reference_table as SELECT * FROM users_table;
|
SELECT create_distributed_table('user_buy_test_table', 'user_id');
|
||||||
SELECT create_reference_table('events_reference_table');
|
create_distributed_table
|
||||||
NOTICE: Copying data from local table...
|
--------------------------
|
||||||
|
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
INSERT INTO user_buy_test_table VALUES(1,2,1);
|
||||||
|
INSERT INTO user_buy_test_table VALUES(2,3,4);
|
||||||
|
INSERT INTO user_buy_test_table VALUES(3,4,2);
|
||||||
|
INSERT INTO user_buy_test_table VALUES(7,5,2);
|
||||||
|
CREATE TABLE users_return_test_table(user_id int, item_id int, buy_count int);
|
||||||
|
SELECT create_distributed_table('users_return_test_table', 'user_id');
|
||||||
|
create_distributed_table
|
||||||
|
--------------------------
|
||||||
|
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
INSERT INTO users_return_test_table VALUES(4,1,1);
|
||||||
|
INSERT INTO users_return_test_table VALUES(1,3,1);
|
||||||
|
INSERT INTO users_return_test_table VALUES(3,2,2);
|
||||||
|
CREATE TABLE users_ref_test_table(id int, it_name varchar(25), k_no int);
|
||||||
|
SELECT create_reference_table('users_ref_test_table');
|
||||||
create_reference_table
|
create_reference_table
|
||||||
------------------------
|
------------------------
|
||||||
|
|
||||||
(1 row)
|
(1 row)
|
||||||
|
|
||||||
SELECT create_reference_table('users_reference_table');
|
INSERT INTO users_ref_test_table VALUES(1,'User_1',45);
|
||||||
NOTICE: Copying data from local table...
|
INSERT INTO users_ref_test_table VALUES(2,'User_2',46);
|
||||||
create_reference_table
|
INSERT INTO users_ref_test_table VALUES(3,'User_3',47);
|
||||||
------------------------
|
INSERT INTO users_ref_test_table VALUES(4,'User_4',48);
|
||||||
|
INSERT INTO users_ref_test_table VALUES(5,'User_5',49);
|
||||||
|
INSERT INTO users_ref_test_table VALUES(6,'User_6',50);
|
||||||
|
-- Simple Join test with reference table
|
||||||
|
SELECT count(*) FROM
|
||||||
|
(SELECT random() FROM user_buy_test_table JOIN users_ref_test_table
|
||||||
|
ON user_buy_test_table.user_id = users_ref_test_table.id) subquery_1;
|
||||||
|
count
|
||||||
|
-------
|
||||||
|
3
|
||||||
(1 row)
|
(1 row)
|
||||||
|
|
||||||
|
-- Should work, reference table at the inner side is allowed
|
||||||
|
SELECT count(*) FROM
|
||||||
|
(SELECT random(), k_no FROM user_buy_test_table LEFT JOIN users_ref_test_table
|
||||||
|
ON user_buy_test_table.user_id = users_ref_test_table.id) subquery_1 WHERE k_no = 47;
|
||||||
|
count
|
||||||
|
-------
|
||||||
|
1
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
-- Should not work, no equality between partition column and reference table
|
||||||
|
SELECT * FROM
|
||||||
|
(SELECT random() FROM user_buy_test_table LEFT JOIN users_ref_test_table
|
||||||
|
ON user_buy_test_table.item_id = users_ref_test_table.id) subquery_1;
|
||||||
|
ERROR: cannot pushdown the subquery since all relations are not joined using distribution keys
|
||||||
|
DETAIL: Each relation should be joined with at least one another relation using distribution keys and equality operator.
|
||||||
|
-- Should not work, no equality between partition column and reference table
|
||||||
|
SELECT * FROM
|
||||||
|
(SELECT random() FROM user_buy_test_table LEFT JOIN users_ref_test_table
|
||||||
|
ON user_buy_test_table.user_id > users_ref_test_table.id) subquery_1;
|
||||||
|
ERROR: cannot pushdown the subquery since all relations are not joined using distribution keys
|
||||||
|
DETAIL: Each relation should be joined with at least one another relation using distribution keys and equality operator.
|
||||||
|
-- Shouldn't work, reference table at the outer side is not allowed
|
||||||
|
SELECT * FROM
|
||||||
|
(SELECT random() FROM users_ref_test_table LEFT JOIN user_buy_test_table
|
||||||
|
ON users_ref_test_table.id = user_buy_test_table.user_id) subquery_1;
|
||||||
|
ERROR: cannot pushdown the subquery
|
||||||
|
DETAIL: There exist a reference table in the outer part of the outer join
|
||||||
|
-- Should work, reference table at the inner side is allowed
|
||||||
|
SELECT count(*) FROM
|
||||||
|
(SELECT random() FROM users_ref_test_table RIGHT JOIN user_buy_test_table
|
||||||
|
ON user_buy_test_table.user_id = users_ref_test_table.id) subquery_1;
|
||||||
|
count
|
||||||
|
-------
|
||||||
|
4
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
-- Shouldn't work, reference table at the outer side is not allowed
|
||||||
|
SELECT * FROM
|
||||||
|
(SELECT random() FROM user_buy_test_table RIGHT JOIN users_ref_test_table
|
||||||
|
ON user_buy_test_table.user_id = users_ref_test_table.id) subquery_1;
|
||||||
|
ERROR: cannot pushdown the subquery
|
||||||
|
DETAIL: There exist a reference table in the outer part of the outer join
|
||||||
|
-- Should pass since reference table locates in the inner part of each left join
|
||||||
|
SELECT count(*) FROM
|
||||||
|
(SELECT tt1.user_id, random() FROM user_buy_test_table AS tt1 JOIN users_return_test_table as tt2
|
||||||
|
ON tt1.user_id = tt2.user_id) subquery_1
|
||||||
|
LEFT JOIN
|
||||||
|
(SELECT tt1.user_id, random() FROM user_buy_test_table as tt1 LEFT JOIN users_ref_test_table as ref
|
||||||
|
ON tt1.user_id = ref.id) subquery_2 ON subquery_1.user_id = subquery_2.user_id;
|
||||||
|
count
|
||||||
|
-------
|
||||||
|
2
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
-- Should not pass since reference table locates in the outer part of right join
|
||||||
|
SELECT * FROM
|
||||||
|
(SELECT tt1.user_id, random() FROM user_buy_test_table AS tt1 JOIN users_return_test_table as tt2
|
||||||
|
ON tt1.user_id = tt2.user_id) subquery_1
|
||||||
|
RIGHT JOIN
|
||||||
|
(SELECT tt1.user_id, random() FROM user_buy_test_table as tt1 JOIN users_ref_test_table as ref
|
||||||
|
ON tt1.user_id = ref.id) subquery_2 ON subquery_1.user_id = subquery_2.user_id;
|
||||||
|
ERROR: cannot pushdown the subquery
|
||||||
|
DETAIL: There exist a reference table in the outer part of the outer join
|
||||||
-- LATERAL JOINs used with INNER JOINs with reference tables
|
-- LATERAL JOINs used with INNER JOINs with reference tables
|
||||||
SET citus.subquery_pushdown to ON;
|
SET citus.subquery_pushdown to ON;
|
||||||
SELECT user_id, lastseen
|
SELECT user_id, lastseen
|
||||||
|
@ -570,3 +660,6 @@ GROUP BY types
|
||||||
ORDER BY types;
|
ORDER BY types;
|
||||||
ERROR: cannot push down this subquery
|
ERROR: cannot push down this subquery
|
||||||
DETAIL: Reference tables are not supported with union operator
|
DETAIL: Reference tables are not supported with union operator
|
||||||
|
DROP TABLE user_buy_test_table;
|
||||||
|
DROP TABLE users_ref_test_table;
|
||||||
|
DROP TABLE users_return_test_table;
|
||||||
|
|
|
@ -28,6 +28,89 @@ LIMIT 5;
|
||||||
63
|
63
|
||||||
(4 rows)
|
(4 rows)
|
||||||
|
|
||||||
|
-- subqueries in WHERE with IN operator
|
||||||
|
SELECT
|
||||||
|
user_id
|
||||||
|
FROM
|
||||||
|
users_table
|
||||||
|
WHERE
|
||||||
|
value_2 IN
|
||||||
|
(SELECT
|
||||||
|
value_2
|
||||||
|
FROM
|
||||||
|
events_reference_table
|
||||||
|
WHERE
|
||||||
|
users_table.user_id = events_reference_table.user_id
|
||||||
|
)
|
||||||
|
GROUP BY user_id
|
||||||
|
ORDER BY user_id
|
||||||
|
LIMIT 3;
|
||||||
|
user_id
|
||||||
|
---------
|
||||||
|
0
|
||||||
|
1
|
||||||
|
2
|
||||||
|
(3 rows)
|
||||||
|
|
||||||
|
-- subqueries in WHERE with NOT EXISTS operator, should work since
|
||||||
|
-- reference table in the inner part of the join
|
||||||
|
SELECT
|
||||||
|
user_id
|
||||||
|
FROM
|
||||||
|
users_table
|
||||||
|
WHERE
|
||||||
|
NOT EXISTS
|
||||||
|
(SELECT
|
||||||
|
value_2
|
||||||
|
FROM
|
||||||
|
events_reference_table
|
||||||
|
WHERE
|
||||||
|
users_table.user_id = events_reference_table.user_id
|
||||||
|
)
|
||||||
|
GROUP BY user_id
|
||||||
|
ORDER BY user_id
|
||||||
|
LIMIT 3;
|
||||||
|
user_id
|
||||||
|
---------
|
||||||
|
(0 rows)
|
||||||
|
|
||||||
|
-- subqueries in WHERE with NOT EXISTS operator, should not work
|
||||||
|
-- there is a reference table in the outer part of the join
|
||||||
|
SELECT
|
||||||
|
user_id
|
||||||
|
FROM
|
||||||
|
users_reference_table
|
||||||
|
WHERE
|
||||||
|
NOT EXISTS
|
||||||
|
(SELECT
|
||||||
|
value_2
|
||||||
|
FROM
|
||||||
|
events_table
|
||||||
|
WHERE
|
||||||
|
users_reference_table.user_id = events_table.user_id
|
||||||
|
)
|
||||||
|
LIMIT 3;
|
||||||
|
ERROR: cannot pushdown the subquery
|
||||||
|
DETAIL: There exist a reference table in the outer part of the outer join
|
||||||
|
-- subqueries in WHERE with IN operator without equality
|
||||||
|
SELECT
|
||||||
|
user_id
|
||||||
|
FROM
|
||||||
|
users_table
|
||||||
|
WHERE
|
||||||
|
value_2 IN
|
||||||
|
(SELECT
|
||||||
|
value_2
|
||||||
|
FROM
|
||||||
|
events_reference_table
|
||||||
|
WHERE
|
||||||
|
users_table.user_id > events_reference_table.user_id
|
||||||
|
)
|
||||||
|
GROUP BY user_id
|
||||||
|
ORDER BY user_id
|
||||||
|
LIMIT 3;
|
||||||
|
ERROR: cannot pushdown the subquery since all relations are not joined using distribution keys
|
||||||
|
DETAIL: Each relation should be joined with at least one another relation using distribution keys and equality operator.
|
||||||
-- have reference table without any equality, should error out
|
-- have reference table without any equality, should error out
|
||||||
SELECT
|
SELECT
|
||||||
user_id
|
user_id
|
||||||
|
@ -141,5 +224,3 @@ SELECT user_id, value_2 FROM users_table WHERE
|
||||||
ORDER BY 1, 2;
|
ORDER BY 1, 2;
|
||||||
ERROR: cannot pushdown the subquery
|
ERROR: cannot pushdown the subquery
|
||||||
DETAIL: There exist a reference table in the outer part of the outer join
|
DETAIL: There exist a reference table in the outer part of the outer join
|
||||||
DROP TABLE events_reference_table;
|
|
||||||
DROP TABLE users_reference_table;
|
|
||||||
|
|
|
@ -23,6 +23,17 @@ LIMIT 5;
|
||||||
20 | 9
|
20 | 9
|
||||||
(5 rows)
|
(5 rows)
|
||||||
|
|
||||||
|
-- a very simple union query with reference table
|
||||||
|
SELECT user_id, counter
|
||||||
|
FROM (
|
||||||
|
SELECT user_id, value_2 % 10 AS counter FROM events_table WHERE event_type IN (1, 2, 3, 4, 5)
|
||||||
|
UNION
|
||||||
|
SELECT user_id, value_2 % 10 AS counter FROM events_reference_table WHERE event_type IN (5, 6, 7, 8, 9, 10)
|
||||||
|
) user_id
|
||||||
|
ORDER BY 2 DESC,1
|
||||||
|
LIMIT 5;
|
||||||
|
ERROR: cannot pushdown this query
|
||||||
|
DETAIL: Reference tables are not allowed with set operations
|
||||||
-- the same query with union all
|
-- the same query with union all
|
||||||
SELECT user_id, counter
|
SELECT user_id, counter
|
||||||
FROM (
|
FROM (
|
||||||
|
@ -41,6 +52,17 @@ LIMIT 5;
|
||||||
15 | 9
|
15 | 9
|
||||||
(5 rows)
|
(5 rows)
|
||||||
|
|
||||||
|
-- the same query with union all and reference table
|
||||||
|
SELECT user_id, counter
|
||||||
|
FROM (
|
||||||
|
SELECT user_id, value_2 % 10 AS counter FROM events_table WHERE event_type IN (1, 2, 3, 4, 5)
|
||||||
|
UNION ALL
|
||||||
|
SELECT user_id, value_2 % 10 AS counter FROM events_reference_table WHERE event_type IN (5, 6, 7, 8, 9, 10)
|
||||||
|
) user_id
|
||||||
|
ORDER BY 2 DESC,1
|
||||||
|
LIMIT 5;
|
||||||
|
ERROR: cannot pushdown this query
|
||||||
|
DETAIL: Reference tables are not allowed with set operations
|
||||||
-- the same query with group by
|
-- the same query with group by
|
||||||
SELECT user_id, sum(counter)
|
SELECT user_id, sum(counter)
|
||||||
FROM (
|
FROM (
|
||||||
|
@ -162,6 +184,22 @@ GROUP BY user_id ORDER BY 1 DESC LIMIT 5;
|
||||||
23508
|
23508
|
||||||
(5 rows)
|
(5 rows)
|
||||||
|
|
||||||
|
-- similar query this time more subqueries with reference table and target list contains a resjunk entry
|
||||||
|
SELECT sum(counter)
|
||||||
|
FROM (
|
||||||
|
SELECT user_id, sum(value_2) AS counter FROM users_table where value_1 < 20 GROUP BY user_id HAVING sum(value_2) > 500
|
||||||
|
UNION
|
||||||
|
SELECT user_id, sum(value_2) AS counter FROM users_table where value_1 < 40 and value_1 < 60 GROUP BY user_id HAVING sum(value_2) > 500
|
||||||
|
UNION
|
||||||
|
SELECT user_id, sum(value_2) AS counter FROM users_reference_table where value_1 < 60 and value_1 < 80 GROUP BY user_id HAVING sum(value_2) > 500
|
||||||
|
UNION
|
||||||
|
SELECT user_id, sum(value_2) AS counter FROM users_table where value_1 < 80 and value_1 < 100 GROUP BY user_id HAVING sum(value_2) > 500
|
||||||
|
UNION
|
||||||
|
SELECT user_id, sum(value_2) AS counter FROM users_table where value_1 < 100 and value_1 < 120 GROUP BY user_id HAVING sum(value_2) > 500
|
||||||
|
) user_id
|
||||||
|
GROUP BY user_id ORDER BY 1 DESC LIMIT 5;
|
||||||
|
ERROR: cannot pushdown this query
|
||||||
|
DETAIL: Reference tables are not allowed with set operations
|
||||||
-- similar query as above, with UNION ALL
|
-- similar query as above, with UNION ALL
|
||||||
SELECT sum(counter)
|
SELECT sum(counter)
|
||||||
FROM (
|
FROM (
|
||||||
|
@ -236,6 +274,50 @@ LIMIT 5;
|
||||||
90 | 115843
|
90 | 115843
|
||||||
(5 rows)
|
(5 rows)
|
||||||
|
|
||||||
|
-- unions within unions with reference table
|
||||||
|
SELECT *
|
||||||
|
FROM (
|
||||||
|
( SELECT user_id,
|
||||||
|
sum(counter)
|
||||||
|
FROM
|
||||||
|
(SELECT
|
||||||
|
user_id, sum(value_2) AS counter
|
||||||
|
FROM
|
||||||
|
users_table
|
||||||
|
GROUP BY
|
||||||
|
user_id
|
||||||
|
UNION
|
||||||
|
SELECT
|
||||||
|
user_id, sum(value_2) AS counter
|
||||||
|
FROM
|
||||||
|
events_reference_table
|
||||||
|
GROUP BY
|
||||||
|
user_id) user_id_1
|
||||||
|
GROUP BY
|
||||||
|
user_id)
|
||||||
|
UNION
|
||||||
|
(SELECT
|
||||||
|
user_id, sum(counter)
|
||||||
|
FROM
|
||||||
|
(SELECT
|
||||||
|
user_id, sum(value_2) AS counter
|
||||||
|
FROM
|
||||||
|
users_table
|
||||||
|
GROUP BY
|
||||||
|
user_id
|
||||||
|
UNION
|
||||||
|
SELECT
|
||||||
|
user_id, sum(value_2) AS counter
|
||||||
|
FROM
|
||||||
|
events_table
|
||||||
|
GROUP BY
|
||||||
|
user_id) user_id_2
|
||||||
|
GROUP BY
|
||||||
|
user_id)) AS ftop
|
||||||
|
ORDER BY 2 DESC, 1 DESC
|
||||||
|
LIMIT 5;
|
||||||
|
ERROR: cannot pushdown this query
|
||||||
|
DETAIL: Reference tables are not allowed with set operations
|
||||||
-- top level unions are wrapped into top level aggregations
|
-- top level unions are wrapped into top level aggregations
|
||||||
SELECT ("final_query"."event_types") as types, count(*) AS sumOfEventType
|
SELECT ("final_query"."event_types") as types, count(*) AS sumOfEventType
|
||||||
FROM
|
FROM
|
||||||
|
@ -493,6 +575,17 @@ FROM
|
||||||
20002
|
20002
|
||||||
(1 row)
|
(1 row)
|
||||||
|
|
||||||
|
-- some UNION ALL queries that are going to be pulled up with reference table
|
||||||
|
SELECT
|
||||||
|
count(*)
|
||||||
|
FROM
|
||||||
|
(
|
||||||
|
(SELECT user_id FROM users_table)
|
||||||
|
UNION ALL
|
||||||
|
(SELECT user_id FROM events_reference_table)
|
||||||
|
) b;
|
||||||
|
ERROR: cannot pushdown this query
|
||||||
|
DETAIL: Reference tables are not allowed with set operations
|
||||||
-- similar query without top level agg
|
-- similar query without top level agg
|
||||||
SELECT
|
SELECT
|
||||||
user_id
|
user_id
|
||||||
|
@ -899,3 +992,5 @@ ORDER BY types;
|
||||||
ERROR: cannot push down this subquery
|
ERROR: cannot push down this subquery
|
||||||
DETAIL: Subqueries without relations are unsupported
|
DETAIL: Subqueries without relations are unsupported
|
||||||
SET citus.enable_router_execution TO true;
|
SET citus.enable_router_execution TO true;
|
||||||
|
DROP TABLE events_reference_table;
|
||||||
|
DROP TABLE users_reference_table;
|
||||||
|
|
|
@ -353,3 +353,11 @@ SET citus.shard_max_size TO "1MB";
|
||||||
|
|
||||||
\copy orders_subquery FROM '@abs_srcdir@/data/orders.1.data' with delimiter '|'
|
\copy orders_subquery FROM '@abs_srcdir@/data/orders.1.data' with delimiter '|'
|
||||||
\copy orders_subquery FROM '@abs_srcdir@/data/orders.2.data' with delimiter '|'
|
\copy orders_subquery FROM '@abs_srcdir@/data/orders.2.data' with delimiter '|'
|
||||||
|
|
||||||
|
CREATE TABLE events_reference_table (like events_table including all);
|
||||||
|
SELECT create_reference_table('events_reference_table');
|
||||||
|
INSERT INTO events_reference_table SELECT * FROM events_table;
|
||||||
|
|
||||||
|
CREATE TABLE users_reference_table (like users_table including all);
|
||||||
|
SELECT create_reference_table('users_reference_table');
|
||||||
|
INSERT INTO users_reference_table SELECT * FROM users_table;
|
||||||
|
|
|
@ -421,3 +421,19 @@ SET citus.shard_max_size TO "1MB";
|
||||||
\copy lineitem_subquery FROM '@abs_srcdir@/data/lineitem.2.data' with delimiter '|'
|
\copy lineitem_subquery FROM '@abs_srcdir@/data/lineitem.2.data' with delimiter '|'
|
||||||
\copy orders_subquery FROM '@abs_srcdir@/data/orders.1.data' with delimiter '|'
|
\copy orders_subquery FROM '@abs_srcdir@/data/orders.1.data' with delimiter '|'
|
||||||
\copy orders_subquery FROM '@abs_srcdir@/data/orders.2.data' with delimiter '|'
|
\copy orders_subquery FROM '@abs_srcdir@/data/orders.2.data' with delimiter '|'
|
||||||
|
CREATE TABLE events_reference_table (like events_table including all);
|
||||||
|
SELECT create_reference_table('events_reference_table');
|
||||||
|
create_reference_table
|
||||||
|
------------------------
|
||||||
|
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
INSERT INTO events_reference_table SELECT * FROM events_table;
|
||||||
|
CREATE TABLE users_reference_table (like users_table including all);
|
||||||
|
SELECT create_reference_table('users_reference_table');
|
||||||
|
create_reference_table
|
||||||
|
------------------------
|
||||||
|
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
INSERT INTO users_reference_table SELECT * FROM users_table;
|
||||||
|
|
|
@ -707,8 +707,7 @@ FROM
|
||||||
WHERE
|
WHERE
|
||||||
colocated_table_test.value_1 = reference_table_test.value_1;
|
colocated_table_test.value_1 = reference_table_test.value_1;
|
||||||
|
|
||||||
-- now, insert into the hash partitioned table and use reference
|
-- not pushable due to lack of equality between partition column and column of reference table
|
||||||
-- tables in the SELECT queries
|
|
||||||
INSERT INTO
|
INSERT INTO
|
||||||
colocated_table_test (value_1, value_2)
|
colocated_table_test (value_1, value_2)
|
||||||
SELECT
|
SELECT
|
||||||
|
|
|
@ -10,11 +10,78 @@ ALTER SEQUENCE pg_catalog.pg_dist_jobid_seq RESTART 1400000;
|
||||||
|
|
||||||
SET citus.enable_router_execution TO FALSE;
|
SET citus.enable_router_execution TO FALSE;
|
||||||
|
|
||||||
CREATE TABLE events_reference_table as SELECT * FROM events_table;
|
CREATE TABLE user_buy_test_table(user_id int, item_id int, buy_count int);
|
||||||
CREATE TABLE users_reference_table as SELECT * FROM users_table;
|
SELECT create_distributed_table('user_buy_test_table', 'user_id');
|
||||||
|
INSERT INTO user_buy_test_table VALUES(1,2,1);
|
||||||
|
INSERT INTO user_buy_test_table VALUES(2,3,4);
|
||||||
|
INSERT INTO user_buy_test_table VALUES(3,4,2);
|
||||||
|
INSERT INTO user_buy_test_table VALUES(7,5,2);
|
||||||
|
|
||||||
SELECT create_reference_table('events_reference_table');
|
CREATE TABLE users_return_test_table(user_id int, item_id int, buy_count int);
|
||||||
SELECT create_reference_table('users_reference_table');
|
SELECT create_distributed_table('users_return_test_table', 'user_id');
|
||||||
|
INSERT INTO users_return_test_table VALUES(4,1,1);
|
||||||
|
INSERT INTO users_return_test_table VALUES(1,3,1);
|
||||||
|
INSERT INTO users_return_test_table VALUES(3,2,2);
|
||||||
|
|
||||||
|
CREATE TABLE users_ref_test_table(id int, it_name varchar(25), k_no int);
|
||||||
|
SELECT create_reference_table('users_ref_test_table');
|
||||||
|
INSERT INTO users_ref_test_table VALUES(1,'User_1',45);
|
||||||
|
INSERT INTO users_ref_test_table VALUES(2,'User_2',46);
|
||||||
|
INSERT INTO users_ref_test_table VALUES(3,'User_3',47);
|
||||||
|
INSERT INTO users_ref_test_table VALUES(4,'User_4',48);
|
||||||
|
INSERT INTO users_ref_test_table VALUES(5,'User_5',49);
|
||||||
|
INSERT INTO users_ref_test_table VALUES(6,'User_6',50);
|
||||||
|
|
||||||
|
-- Simple Join test with reference table
|
||||||
|
SELECT count(*) FROM
|
||||||
|
(SELECT random() FROM user_buy_test_table JOIN users_ref_test_table
|
||||||
|
ON user_buy_test_table.user_id = users_ref_test_table.id) subquery_1;
|
||||||
|
|
||||||
|
-- Should work, reference table at the inner side is allowed
|
||||||
|
SELECT count(*) FROM
|
||||||
|
(SELECT random(), k_no FROM user_buy_test_table LEFT JOIN users_ref_test_table
|
||||||
|
ON user_buy_test_table.user_id = users_ref_test_table.id) subquery_1 WHERE k_no = 47;
|
||||||
|
|
||||||
|
-- Should not work, no equality between partition column and reference table
|
||||||
|
SELECT * FROM
|
||||||
|
(SELECT random() FROM user_buy_test_table LEFT JOIN users_ref_test_table
|
||||||
|
ON user_buy_test_table.item_id = users_ref_test_table.id) subquery_1;
|
||||||
|
|
||||||
|
-- Should not work, no equality between partition column and reference table
|
||||||
|
SELECT * FROM
|
||||||
|
(SELECT random() FROM user_buy_test_table LEFT JOIN users_ref_test_table
|
||||||
|
ON user_buy_test_table.user_id > users_ref_test_table.id) subquery_1;
|
||||||
|
|
||||||
|
-- Shouldn't work, reference table at the outer side is not allowed
|
||||||
|
SELECT * FROM
|
||||||
|
(SELECT random() FROM users_ref_test_table LEFT JOIN user_buy_test_table
|
||||||
|
ON users_ref_test_table.id = user_buy_test_table.user_id) subquery_1;
|
||||||
|
|
||||||
|
-- Should work, reference table at the inner side is allowed
|
||||||
|
SELECT count(*) FROM
|
||||||
|
(SELECT random() FROM users_ref_test_table RIGHT JOIN user_buy_test_table
|
||||||
|
ON user_buy_test_table.user_id = users_ref_test_table.id) subquery_1;
|
||||||
|
|
||||||
|
-- Shouldn't work, reference table at the outer side is not allowed
|
||||||
|
SELECT * FROM
|
||||||
|
(SELECT random() FROM user_buy_test_table RIGHT JOIN users_ref_test_table
|
||||||
|
ON user_buy_test_table.user_id = users_ref_test_table.id) subquery_1;
|
||||||
|
|
||||||
|
-- Should pass since reference table locates in the inner part of each left join
|
||||||
|
SELECT count(*) FROM
|
||||||
|
(SELECT tt1.user_id, random() FROM user_buy_test_table AS tt1 JOIN users_return_test_table as tt2
|
||||||
|
ON tt1.user_id = tt2.user_id) subquery_1
|
||||||
|
LEFT JOIN
|
||||||
|
(SELECT tt1.user_id, random() FROM user_buy_test_table as tt1 LEFT JOIN users_ref_test_table as ref
|
||||||
|
ON tt1.user_id = ref.id) subquery_2 ON subquery_1.user_id = subquery_2.user_id;
|
||||||
|
|
||||||
|
-- Should not pass since reference table locates in the outer part of right join
|
||||||
|
SELECT * FROM
|
||||||
|
(SELECT tt1.user_id, random() FROM user_buy_test_table AS tt1 JOIN users_return_test_table as tt2
|
||||||
|
ON tt1.user_id = tt2.user_id) subquery_1
|
||||||
|
RIGHT JOIN
|
||||||
|
(SELECT tt1.user_id, random() FROM user_buy_test_table as tt1 JOIN users_ref_test_table as ref
|
||||||
|
ON tt1.user_id = ref.id) subquery_2 ON subquery_1.user_id = subquery_2.user_id;
|
||||||
|
|
||||||
-- LATERAL JOINs used with INNER JOINs with reference tables
|
-- LATERAL JOINs used with INNER JOINs with reference tables
|
||||||
SET citus.subquery_pushdown to ON;
|
SET citus.subquery_pushdown to ON;
|
||||||
|
@ -501,3 +568,7 @@ INNER JOIN
|
||||||
WHERE value_1 > 50 and value_1 < 70) AS t ON (t.user_id = q.user_id)) as final_query
|
WHERE value_1 > 50 and value_1 < 70) AS t ON (t.user_id = q.user_id)) as final_query
|
||||||
GROUP BY types
|
GROUP BY types
|
||||||
ORDER BY types;
|
ORDER BY types;
|
||||||
|
|
||||||
|
DROP TABLE user_buy_test_table;
|
||||||
|
DROP TABLE users_ref_test_table;
|
||||||
|
DROP TABLE users_return_test_table;
|
||||||
|
|
|
@ -22,6 +22,78 @@ HAVING count(*) > 66
|
||||||
ORDER BY user_id
|
ORDER BY user_id
|
||||||
LIMIT 5;
|
LIMIT 5;
|
||||||
|
|
||||||
|
-- subqueries in WHERE with IN operator
|
||||||
|
SELECT
|
||||||
|
user_id
|
||||||
|
FROM
|
||||||
|
users_table
|
||||||
|
WHERE
|
||||||
|
value_2 IN
|
||||||
|
(SELECT
|
||||||
|
value_2
|
||||||
|
FROM
|
||||||
|
events_reference_table
|
||||||
|
WHERE
|
||||||
|
users_table.user_id = events_reference_table.user_id
|
||||||
|
)
|
||||||
|
GROUP BY user_id
|
||||||
|
ORDER BY user_id
|
||||||
|
LIMIT 3;
|
||||||
|
|
||||||
|
-- subqueries in WHERE with NOT EXISTS operator, should work since
|
||||||
|
-- reference table in the inner part of the join
|
||||||
|
SELECT
|
||||||
|
user_id
|
||||||
|
FROM
|
||||||
|
users_table
|
||||||
|
WHERE
|
||||||
|
NOT EXISTS
|
||||||
|
(SELECT
|
||||||
|
value_2
|
||||||
|
FROM
|
||||||
|
events_reference_table
|
||||||
|
WHERE
|
||||||
|
users_table.user_id = events_reference_table.user_id
|
||||||
|
)
|
||||||
|
GROUP BY user_id
|
||||||
|
ORDER BY user_id
|
||||||
|
LIMIT 3;
|
||||||
|
|
||||||
|
-- subqueries in WHERE with NOT EXISTS operator, should not work
|
||||||
|
-- there is a reference table in the outer part of the join
|
||||||
|
SELECT
|
||||||
|
user_id
|
||||||
|
FROM
|
||||||
|
users_reference_table
|
||||||
|
WHERE
|
||||||
|
NOT EXISTS
|
||||||
|
(SELECT
|
||||||
|
value_2
|
||||||
|
FROM
|
||||||
|
events_table
|
||||||
|
WHERE
|
||||||
|
users_reference_table.user_id = events_table.user_id
|
||||||
|
)
|
||||||
|
LIMIT 3;
|
||||||
|
|
||||||
|
-- subqueries in WHERE with IN operator without equality
|
||||||
|
SELECT
|
||||||
|
user_id
|
||||||
|
FROM
|
||||||
|
users_table
|
||||||
|
WHERE
|
||||||
|
value_2 IN
|
||||||
|
(SELECT
|
||||||
|
value_2
|
||||||
|
FROM
|
||||||
|
events_reference_table
|
||||||
|
WHERE
|
||||||
|
users_table.user_id > events_reference_table.user_id
|
||||||
|
)
|
||||||
|
GROUP BY user_id
|
||||||
|
ORDER BY user_id
|
||||||
|
LIMIT 3;
|
||||||
|
|
||||||
-- have reference table without any equality, should error out
|
-- have reference table without any equality, should error out
|
||||||
SELECT
|
SELECT
|
||||||
user_id
|
user_id
|
||||||
|
@ -125,6 +197,3 @@ SELECT user_id, value_2 FROM users_table WHERE
|
||||||
HAVING sum(submit_card_info) > 0
|
HAVING sum(submit_card_info) > 0
|
||||||
)
|
)
|
||||||
ORDER BY 1, 2;
|
ORDER BY 1, 2;
|
||||||
|
|
||||||
DROP TABLE events_reference_table;
|
|
||||||
DROP TABLE users_reference_table;
|
|
|
@ -17,6 +17,16 @@ FROM (
|
||||||
ORDER BY 2 DESC,1
|
ORDER BY 2 DESC,1
|
||||||
LIMIT 5;
|
LIMIT 5;
|
||||||
|
|
||||||
|
-- a very simple union query with reference table
|
||||||
|
SELECT user_id, counter
|
||||||
|
FROM (
|
||||||
|
SELECT user_id, value_2 % 10 AS counter FROM events_table WHERE event_type IN (1, 2, 3, 4, 5)
|
||||||
|
UNION
|
||||||
|
SELECT user_id, value_2 % 10 AS counter FROM events_reference_table WHERE event_type IN (5, 6, 7, 8, 9, 10)
|
||||||
|
) user_id
|
||||||
|
ORDER BY 2 DESC,1
|
||||||
|
LIMIT 5;
|
||||||
|
|
||||||
-- the same query with union all
|
-- the same query with union all
|
||||||
SELECT user_id, counter
|
SELECT user_id, counter
|
||||||
FROM (
|
FROM (
|
||||||
|
@ -27,6 +37,16 @@ FROM (
|
||||||
ORDER BY 2 DESC,1
|
ORDER BY 2 DESC,1
|
||||||
LIMIT 5;
|
LIMIT 5;
|
||||||
|
|
||||||
|
-- the same query with union all and reference table
|
||||||
|
SELECT user_id, counter
|
||||||
|
FROM (
|
||||||
|
SELECT user_id, value_2 % 10 AS counter FROM events_table WHERE event_type IN (1, 2, 3, 4, 5)
|
||||||
|
UNION ALL
|
||||||
|
SELECT user_id, value_2 % 10 AS counter FROM events_reference_table WHERE event_type IN (5, 6, 7, 8, 9, 10)
|
||||||
|
) user_id
|
||||||
|
ORDER BY 2 DESC,1
|
||||||
|
LIMIT 5;
|
||||||
|
|
||||||
-- the same query with group by
|
-- the same query with group by
|
||||||
SELECT user_id, sum(counter)
|
SELECT user_id, sum(counter)
|
||||||
FROM (
|
FROM (
|
||||||
|
@ -102,6 +122,21 @@ FROM (
|
||||||
) user_id
|
) user_id
|
||||||
GROUP BY user_id ORDER BY 1 DESC LIMIT 5;
|
GROUP BY user_id ORDER BY 1 DESC LIMIT 5;
|
||||||
|
|
||||||
|
-- similar query this time more subqueries with reference table and target list contains a resjunk entry
|
||||||
|
SELECT sum(counter)
|
||||||
|
FROM (
|
||||||
|
SELECT user_id, sum(value_2) AS counter FROM users_table where value_1 < 20 GROUP BY user_id HAVING sum(value_2) > 500
|
||||||
|
UNION
|
||||||
|
SELECT user_id, sum(value_2) AS counter FROM users_table where value_1 < 40 and value_1 < 60 GROUP BY user_id HAVING sum(value_2) > 500
|
||||||
|
UNION
|
||||||
|
SELECT user_id, sum(value_2) AS counter FROM users_reference_table where value_1 < 60 and value_1 < 80 GROUP BY user_id HAVING sum(value_2) > 500
|
||||||
|
UNION
|
||||||
|
SELECT user_id, sum(value_2) AS counter FROM users_table where value_1 < 80 and value_1 < 100 GROUP BY user_id HAVING sum(value_2) > 500
|
||||||
|
UNION
|
||||||
|
SELECT user_id, sum(value_2) AS counter FROM users_table where value_1 < 100 and value_1 < 120 GROUP BY user_id HAVING sum(value_2) > 500
|
||||||
|
) user_id
|
||||||
|
GROUP BY user_id ORDER BY 1 DESC LIMIT 5;
|
||||||
|
|
||||||
-- similar query as above, with UNION ALL
|
-- similar query as above, with UNION ALL
|
||||||
SELECT sum(counter)
|
SELECT sum(counter)
|
||||||
FROM (
|
FROM (
|
||||||
|
@ -160,6 +195,49 @@ FROM (
|
||||||
ORDER BY 2 DESC, 1 DESC
|
ORDER BY 2 DESC, 1 DESC
|
||||||
LIMIT 5;
|
LIMIT 5;
|
||||||
|
|
||||||
|
-- unions within unions with reference table
|
||||||
|
SELECT *
|
||||||
|
FROM (
|
||||||
|
( SELECT user_id,
|
||||||
|
sum(counter)
|
||||||
|
FROM
|
||||||
|
(SELECT
|
||||||
|
user_id, sum(value_2) AS counter
|
||||||
|
FROM
|
||||||
|
users_table
|
||||||
|
GROUP BY
|
||||||
|
user_id
|
||||||
|
UNION
|
||||||
|
SELECT
|
||||||
|
user_id, sum(value_2) AS counter
|
||||||
|
FROM
|
||||||
|
events_reference_table
|
||||||
|
GROUP BY
|
||||||
|
user_id) user_id_1
|
||||||
|
GROUP BY
|
||||||
|
user_id)
|
||||||
|
UNION
|
||||||
|
(SELECT
|
||||||
|
user_id, sum(counter)
|
||||||
|
FROM
|
||||||
|
(SELECT
|
||||||
|
user_id, sum(value_2) AS counter
|
||||||
|
FROM
|
||||||
|
users_table
|
||||||
|
GROUP BY
|
||||||
|
user_id
|
||||||
|
UNION
|
||||||
|
SELECT
|
||||||
|
user_id, sum(value_2) AS counter
|
||||||
|
FROM
|
||||||
|
events_table
|
||||||
|
GROUP BY
|
||||||
|
user_id) user_id_2
|
||||||
|
GROUP BY
|
||||||
|
user_id)) AS ftop
|
||||||
|
ORDER BY 2 DESC, 1 DESC
|
||||||
|
LIMIT 5;
|
||||||
|
|
||||||
-- top level unions are wrapped into top level aggregations
|
-- top level unions are wrapped into top level aggregations
|
||||||
SELECT ("final_query"."event_types") as types, count(*) AS sumOfEventType
|
SELECT ("final_query"."event_types") as types, count(*) AS sumOfEventType
|
||||||
FROM
|
FROM
|
||||||
|
@ -377,6 +455,16 @@ FROM
|
||||||
(SELECT user_id FROM events_table)
|
(SELECT user_id FROM events_table)
|
||||||
) b;
|
) b;
|
||||||
|
|
||||||
|
-- some UNION ALL queries that are going to be pulled up with reference table
|
||||||
|
SELECT
|
||||||
|
count(*)
|
||||||
|
FROM
|
||||||
|
(
|
||||||
|
(SELECT user_id FROM users_table)
|
||||||
|
UNION ALL
|
||||||
|
(SELECT user_id FROM events_reference_table)
|
||||||
|
) b;
|
||||||
|
|
||||||
-- similar query without top level agg
|
-- similar query without top level agg
|
||||||
SELECT
|
SELECT
|
||||||
user_id
|
user_id
|
||||||
|
@ -724,3 +812,6 @@ GROUP BY types
|
||||||
ORDER BY types;
|
ORDER BY types;
|
||||||
|
|
||||||
SET citus.enable_router_execution TO true;
|
SET citus.enable_router_execution TO true;
|
||||||
|
|
||||||
|
DROP TABLE events_reference_table;
|
||||||
|
DROP TABLE users_reference_table;
|
||||||
|
|
Loading…
Reference in New Issue