Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -177,7 +177,7 @@ abstract class Optimizer(catalogManager: CatalogManager)
// to enforce idempotence on it and we change this batch from Once to FixedPoint(1).
Batch("Subquery", FixedPoint(1),
OptimizeSubqueries) ::
Batch("Replace Operators", fixedPoint,
Batch("Replace Operators", Once,
RewriteExceptAll,
RewriteIntersectAll,
ReplaceIntersectWithSemiJoin,
Expand Down Expand Up @@ -1615,7 +1615,9 @@ object ConvertToLocalRelation extends Rule[LogicalPlan] {
* }}}
*/
object ReplaceDistinctWithAggregate extends Rule[LogicalPlan] {
def apply(plan: LogicalPlan): LogicalPlan = plan transform {
def apply(plan: LogicalPlan): LogicalPlan = plan transformDown {
// The [[Distinct]] can be ignored if it is the right child of a left semi or anti join.
case j @ Join(_, Distinct(right), LeftSemiOrAnti(_), _, _) => j.copy(right = right)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just out of curiosity, this rule can always make performance better? For example, how about the case where a right table has too many duplicates?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I benchmarked a bit and you are right - this can cause a performance regression. For example q87 took a 10% hit on sf100. I think it's best to close this PR and issue.

case Distinct(child) => Aggregate(child.output, child.output, child)
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,30 @@ class ReplaceOperatorSuite extends PlanTest {
comparePlans(optimized, correctAnswer)
}

test("SPARK-34014: Ignore Distinct if it is the right child of a left semi join") {
val x = LocalRelation('x1.int, 'x2.int)
val y = LocalRelation('y1.int, 'y2.int)

val query = x.join(Distinct(y), LeftSemi, Some('x1 === 'y1))
val optimized = Optimize.execute(query.analyze)

val correctAnswer = x.join(y, LeftSemi, Some('x1 === 'y1)).analyze

comparePlans(optimized, correctAnswer)
}

test("SPARK-34014: Ignore Distinct if it is the right child of a left anti join") {
val x = LocalRelation('x1.int, 'x2.int)
val y = LocalRelation('y1.int, 'y2.int)

val query = x.join(Distinct(y), LeftAnti, Some('x1 === 'y1))
val optimized = Optimize.execute(query.analyze)

val correctAnswer = x.join(y, LeftAnti, Some('x1 === 'y1)).analyze

comparePlans(optimized, correctAnswer)
}

test("replace batch Deduplicate with Aggregate") {
val input = LocalRelation('a.int, 'b.int)
val attrA = input.output(0)
Expand Down

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
WholeStageCodegen (26)
WholeStageCodegen (24)
HashAggregate [count] [count(1),count(1),count]
InputAdapter
Exchange #1
WholeStageCodegen (25)
WholeStageCodegen (23)
HashAggregate [count,count]
HashAggregate [c_last_name,c_first_name,d_date]
HashAggregate [c_last_name,c_first_name,d_date]
Expand All @@ -11,7 +11,7 @@ WholeStageCodegen (26)
HashAggregate [c_last_name,c_first_name,d_date]
InputAdapter
Exchange [c_last_name,c_first_name,d_date] #2
WholeStageCodegen (24)
WholeStageCodegen (22)
HashAggregate [c_last_name,c_first_name,d_date]
InputAdapter
SortMergeJoin [c_last_name,c_first_name,d_date,c_last_name,c_first_name,d_date]
Expand Down Expand Up @@ -53,65 +53,55 @@ WholeStageCodegen (26)
ColumnarToRow
InputAdapter
Scan parquet default.customer [c_customer_sk,c_first_name,c_last_name]
WholeStageCodegen (15)
WholeStageCodegen (14)
Sort [c_last_name,c_first_name,d_date]
InputAdapter
Exchange [c_last_name,c_first_name,d_date] #7
WholeStageCodegen (14)
HashAggregate [c_last_name,c_first_name,d_date]
InputAdapter
Exchange [c_last_name,c_first_name,d_date] #8
WholeStageCodegen (13)
HashAggregate [c_last_name,c_first_name,d_date]
Project [c_last_name,c_first_name,d_date]
SortMergeJoin [cs_bill_customer_sk,c_customer_sk]
InputAdapter
WholeStageCodegen (10)
Sort [cs_bill_customer_sk]
InputAdapter
Exchange [cs_bill_customer_sk] #9
WholeStageCodegen (9)
Project [cs_bill_customer_sk,d_date]
BroadcastHashJoin [cs_sold_date_sk,d_date_sk]
Filter [cs_sold_date_sk,cs_bill_customer_sk]
ColumnarToRow
InputAdapter
Scan parquet default.catalog_sales [cs_sold_date_sk,cs_bill_customer_sk]
InputAdapter
ReusedExchange [d_date_sk,d_date] #5
InputAdapter
WholeStageCodegen (12)
Sort [c_customer_sk]
WholeStageCodegen (13)
Project [c_last_name,c_first_name,d_date]
SortMergeJoin [cs_bill_customer_sk,c_customer_sk]
InputAdapter
WholeStageCodegen (10)
Sort [cs_bill_customer_sk]
InputAdapter
Exchange [cs_bill_customer_sk] #8
WholeStageCodegen (9)
Project [cs_bill_customer_sk,d_date]
BroadcastHashJoin [cs_sold_date_sk,d_date_sk]
Filter [cs_sold_date_sk,cs_bill_customer_sk]
ColumnarToRow
InputAdapter
Scan parquet default.catalog_sales [cs_sold_date_sk,cs_bill_customer_sk]
InputAdapter
ReusedExchange [c_customer_sk,c_first_name,c_last_name] #6
WholeStageCodegen (23)
ReusedExchange [d_date_sk,d_date] #5
InputAdapter
WholeStageCodegen (12)
Sort [c_customer_sk]
InputAdapter
ReusedExchange [c_customer_sk,c_first_name,c_last_name] #6
WholeStageCodegen (21)
Sort [c_last_name,c_first_name,d_date]
InputAdapter
Exchange [c_last_name,c_first_name,d_date] #10
WholeStageCodegen (22)
HashAggregate [c_last_name,c_first_name,d_date]
InputAdapter
Exchange [c_last_name,c_first_name,d_date] #11
WholeStageCodegen (21)
HashAggregate [c_last_name,c_first_name,d_date]
Project [c_last_name,c_first_name,d_date]
SortMergeJoin [ws_bill_customer_sk,c_customer_sk]
InputAdapter
WholeStageCodegen (18)
Sort [ws_bill_customer_sk]
InputAdapter
Exchange [ws_bill_customer_sk] #12
WholeStageCodegen (17)
Project [ws_bill_customer_sk,d_date]
BroadcastHashJoin [ws_sold_date_sk,d_date_sk]
Filter [ws_sold_date_sk,ws_bill_customer_sk]
ColumnarToRow
InputAdapter
Scan parquet default.web_sales [ws_sold_date_sk,ws_bill_customer_sk]
InputAdapter
ReusedExchange [d_date_sk,d_date] #5
InputAdapter
WholeStageCodegen (20)
Sort [c_customer_sk]
Exchange [c_last_name,c_first_name,d_date] #9
WholeStageCodegen (20)
Project [c_last_name,c_first_name,d_date]
SortMergeJoin [ws_bill_customer_sk,c_customer_sk]
InputAdapter
WholeStageCodegen (17)
Sort [ws_bill_customer_sk]
InputAdapter
Exchange [ws_bill_customer_sk] #10
WholeStageCodegen (16)
Project [ws_bill_customer_sk,d_date]
BroadcastHashJoin [ws_sold_date_sk,d_date_sk]
Filter [ws_sold_date_sk,ws_bill_customer_sk]
ColumnarToRow
InputAdapter
Scan parquet default.web_sales [ws_sold_date_sk,ws_bill_customer_sk]
InputAdapter
ReusedExchange [c_customer_sk,c_first_name,c_last_name] #6
ReusedExchange [d_date_sk,d_date] #5
InputAdapter
WholeStageCodegen (19)
Sort [c_customer_sk]
InputAdapter
ReusedExchange [c_customer_sk,c_first_name,c_last_name] #6
Loading