diff --git a/pkg/planner/core/operator/logicalop/logical_join.go b/pkg/planner/core/operator/logicalop/logical_join.go index 72ea8eb4f5aab..8ce6482ebfccb 100644 --- a/pkg/planner/core/operator/logicalop/logical_join.go +++ b/pkg/planner/core/operator/logicalop/logical_join.go @@ -510,6 +510,27 @@ func (p *LogicalJoin) PushDownTopN(topNLogicalPlan base.LogicalPlan) base.Logica case base.RightOuterJoin: p.Children()[1], topnEliminated = p.pushDownTopNToChild(topN, 1) p.Children()[0] = p.Children()[0].PushDownTopN(nil) + case base.InnerJoin: + if p.canPushLimitDownToCartesianChildren(topN) { + limitCount, carry := bits.Add64(topN.Count, topN.Offset, 0) + if carry > 0 { + limitCount = math.MaxUint64 + } + leftLimit := LogicalTopN{ + Count: limitCount, + Offset: 0, + PreferLimitToCop: topN.PreferLimitToCop, + }.Init(topN.SCtx(), topN.QueryBlockOffset()) + rightLimit := LogicalTopN{ + Count: limitCount, + Offset: 0, + PreferLimitToCop: topN.PreferLimitToCop, + }.Init(topN.SCtx(), topN.QueryBlockOffset()) + p.Children()[0] = p.Children()[0].PushDownTopN(leftLimit) + p.Children()[1] = p.Children()[1].PushDownTopN(rightLimit) + return topN.AttachChild(p.Self()) + } + return p.BaseLogicalPlan.PushDownTopN(topN) default: return p.BaseLogicalPlan.PushDownTopN(topN) } @@ -531,6 +552,20 @@ func (p *LogicalJoin) PushDownTopN(topNLogicalPlan base.LogicalPlan) base.Logica return p.Self() } +func (p *LogicalJoin) canPushLimitDownToCartesianChildren(topN *LogicalTopN) bool { + if topN == nil || !topN.IsLimit() { + return false + } + if _, isApply := p.Self().(*LogicalApply); isApply { + return false + } + return len(p.EqualConditions) == 0 && + len(p.NAEQConditions) == 0 && + len(p.LeftConditions) == 0 && + len(p.RightConditions) == 0 && + len(p.OtherConditions) == 0 +} + // DeriveTopN inherits the BaseLogicalPlan.LogicalPlan.<6th> implementation. // PredicateSimplification inherits the BaseLogicalPlan.LogicalPlan.<7th> implementation. diff --git a/pkg/planner/core/testdata/plan_suite_unexported_out.json b/pkg/planner/core/testdata/plan_suite_unexported_out.json index 673752ce18199..33580446bb20e 100644 --- a/pkg/planner/core/testdata/plan_suite_unexported_out.json +++ b/pkg/planner/core/testdata/plan_suite_unexported_out.json @@ -148,7 +148,7 @@ "DataScan(t)->Aggr(count(test.t.b),firstrow(test.t.a))->Limit->Projection", "DataScan(t)->Aggr(count(test.t.b),firstrow(test.t.a),firstrow(test.t.c))->TopN([test.t.c],0,5)->Projection", "Join{DataScan(t)->DataScan(s)}->TopN([test.t.a],0,5)->Projection", - "Join{DataScan(t)->DataScan(s)}->Limit->Projection", + "Join{DataScan(t)->Limit->DataScan(s)->Limit}->Limit->Projection", "DataScan(t)->Projection->TopN([Column#14 true],0,1)->Projection", "Join{DataScan(t)->TopN([test.t.a],0,5)->DataScan(s)}(test.t.a,test.t.a)->Sort->Projection", "Join{DataScan(t)->TopN([test.t.a],5,5)->DataScan(s)}(test.t.a,test.t.a)->Sort->Projection",