Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

planner/core: refine explain for window function #9270

Merged
merged 4 commits into from
Feb 13, 2019
Merged
Show file tree
Hide file tree
Changes from 3 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
1 change: 1 addition & 0 deletions cmd/explaintest/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@ func newTester(name string) *tester {
t.name = name
t.enableQueryLog = true
t.ctx = mock.NewContext()
t.ctx.GetSessionVars().EnableWindowFunction = true

return t
}
Expand Down
51 changes: 51 additions & 0 deletions cmd/explaintest/r/window_function.result
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
use test;
drop table if exists t;
create table t (a int, b int, c timestamp, index idx(a));
set @@tidb_enable_window_function = 1;
explain select sum(a) over() from t;
id count task operator info
Projection_7 10000.00 root sum(a) over()
└─Window_8 10000.00 root sum(cast(test.t.a)) over()
└─TableReader_10 10000.00 root data:TableScan_9
└─TableScan_9 10000.00 cop table:t, range:[-inf,+inf], keep order:false, stats:pseudo
explain select sum(a) over(partition by a) from t;
id count task operator info
Projection_7 10000.00 root sum(a) over(partition by a)
└─Window_8 10000.00 root sum(cast(test.t.a)) over(partition by test.t.a)
└─IndexReader_11 10000.00 root index:IndexScan_10
└─IndexScan_10 10000.00 cop table:t, index:a, range:[NULL,+inf], keep order:true, stats:pseudo
explain select sum(a) over(partition by a order by b) from t;
id count task operator info
Projection_7 10000.00 root sum(a) over(partition by a order by b)
└─Window_8 10000.00 root sum(cast(test.t.a)) over(partition by test.t.a order by test.t.b asc)
└─Sort_14 10000.00 root test.t.a:asc, test.t.b:asc
└─TableReader_13 10000.00 root data:TableScan_12
└─TableScan_12 10000.00 cop table:t, range:[-inf,+inf], keep order:false, stats:pseudo
explain select sum(a) over(partition by a order by b rows unbounded preceding) from t;
id count task operator info
Projection_7 10000.00 root sum(a) over(partition by a order by b rows unbounded preceding)
└─Window_8 10000.00 root sum(cast(test.t.a)) over(partition by test.t.a order by test.t.b asc rows between unbounded preceding and current row)
└─Sort_14 10000.00 root test.t.a:asc, test.t.b:asc
└─TableReader_13 10000.00 root data:TableScan_12
└─TableScan_12 10000.00 cop table:t, range:[-inf,+inf], keep order:false, stats:pseudo
explain select sum(a) over(partition by a order by b rows between 1 preceding and 1 following) from t;
id count task operator info
Projection_7 10000.00 root sum(a) over(partition by a order by b rows between 1 preceding and 1 following)
└─Window_8 10000.00 root sum(cast(test.t.a)) over(partition by test.t.a order by test.t.b asc rows between 1 preceding and 1 following)
└─Sort_14 10000.00 root test.t.a:asc, test.t.b:asc
└─TableReader_13 10000.00 root data:TableScan_12
└─TableScan_12 10000.00 cop table:t, range:[-inf,+inf], keep order:false, stats:pseudo
explain select sum(a) over(partition by a order by b range between 1 preceding and 1 following) from t;
id count task operator info
Projection_7 10000.00 root sum(a) over(partition by a order by b range between 1 preceding and 1 following)
└─Window_8 10000.00 root sum(cast(test.t.a)) over(partition by test.t.a order by test.t.b asc range between 1 preceding and 1 following)
└─Sort_14 10000.00 root test.t.a:asc, test.t.b:asc
└─TableReader_13 10000.00 root data:TableScan_12
└─TableScan_12 10000.00 cop table:t, range:[-inf,+inf], keep order:false, stats:pseudo
explain select sum(a) over(partition by a order by c range between interval '2:30' minute_second preceding and interval '2:30' minute_second following) from t;
id count task operator info
Projection_7 10000.00 root sum(a) over(partition by a order by c range between interval '2:30' minute_second preceding and interval '2:30' minute_second following)
└─Window_8 10000.00 root sum(cast(test.t.a)) over(partition by test.t.a order by test.t.c asc range between interval "2:30" "MINUTE_SECOND" preceding and interval "2:30" "MINUTE_SECOND" following)
└─Sort_14 10000.00 root test.t.a:asc, test.t.c:asc
└─TableReader_13 10000.00 root data:TableScan_12
└─TableScan_12 10000.00 cop table:t, range:[-inf,+inf], keep order:false, stats:pseudo
11 changes: 11 additions & 0 deletions cmd/explaintest/t/window_function.test
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
use test;
drop table if exists t;
create table t (a int, b int, c timestamp, index idx(a));
set @@tidb_enable_window_function = 1;
explain select sum(a) over() from t;
explain select sum(a) over(partition by a) from t;
explain select sum(a) over(partition by a order by b) from t;
explain select sum(a) over(partition by a order by b rows unbounded preceding) from t;
explain select sum(a) over(partition by a order by b rows between 1 preceding and 1 following) from t;
explain select sum(a) over(partition by a order by b range between 1 preceding and 1 following) from t;
explain select sum(a) over(partition by a order by c range between interval '2:30' minute_second preceding and interval '2:30' minute_second following) from t;
1 change: 1 addition & 0 deletions planner/core/exhaust_physical_plans.go
Original file line number Diff line number Diff line change
Expand Up @@ -783,6 +783,7 @@ func (p *LogicalWindow) exhaustPhysicalPlans(prop *property.PhysicalProperty) []
WindowFuncDesc: p.WindowFuncDesc,
PartitionBy: p.PartitionBy,
OrderBy: p.OrderBy,
Frame: p.Frame,
}.Init(p.ctx, p.stats.ScaleByExpectCnt(prop.ExpectedCnt), childProperty)
window.SetSchema(p.Schema())
return []PhysicalPlan{window}
Expand Down
70 changes: 68 additions & 2 deletions planner/core/explain.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import (
"bytes"
"fmt"

"github.com/pingcap/parser/ast"
"github.com/pingcap/tidb/expression"
"github.com/pingcap/tidb/expression/aggregation"
)
Expand Down Expand Up @@ -298,8 +299,73 @@ func (p *PhysicalTopN) ExplainInfo() string {
return buffer.String()
}

func (p *PhysicalWindow) formatFrameBound(buffer *bytes.Buffer, bound *FrameBound) {
if bound.Type == ast.CurrentRow {
buffer.WriteString("current row")
return
}
if bound.UnBounded {
buffer.WriteString("unbounded")
} else if bound.DateCalcFunc != nil {
sf := bound.DateCalcFunc.(*expression.ScalarFunction)
// for `interval '2:30' minute_second`.
fmt.Fprintf(buffer, "interval %s %s", sf.GetArgs()[1].ExplainInfo(), sf.GetArgs()[2].ExplainInfo())
} else {
fmt.Fprintf(buffer, "%d", bound.Num)
}
if bound.Type == ast.Preceding {
buffer.WriteString(" preceding")
} else {
buffer.WriteString(" following")
}
}

// ExplainInfo implements PhysicalPlan interface.
func (p *PhysicalWindow) ExplainInfo() string {
// TODO: Add explain info for partition by, order by and frame.
return p.WindowFuncDesc.String()
buffer := bytes.NewBufferString(p.WindowFuncDesc.String())
buffer.WriteString(" over(")
isFirst := true
if len(p.PartitionBy) > 0 {
buffer.WriteString("partition by ")
for i, item := range p.PartitionBy {
fmt.Fprintf(buffer, "%s", item.Col.ExplainInfo())
if i+1 < len(p.PartitionBy) {
buffer.WriteString(", ")
}
}
isFirst = false
}
if len(p.OrderBy) > 0 {
if !isFirst {
buffer.WriteString(" ")
}
buffer.WriteString("order by ")
for i, item := range p.OrderBy {
order := "asc"
if item.Desc {
order = "desc"
}
fmt.Fprintf(buffer, "%s %s", item.Col.ExplainInfo(), order)
if i+1 < len(p.OrderBy) {
buffer.WriteString(", ")
}
}
isFirst = false
}
if p.Frame != nil {
if !isFirst {
buffer.WriteString(" ")
}
if p.Frame.Type == ast.Rows {
buffer.WriteString("rows")
} else {
buffer.WriteString("range")
}
buffer.WriteString(" between ")
p.formatFrameBound(buffer, p.Frame.Start)
buffer.WriteString(" and ")
p.formatFrameBound(buffer, p.Frame.End)
}
buffer.WriteString(")")
return buffer.String()
}
26 changes: 13 additions & 13 deletions planner/core/logical_plan_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1915,51 +1915,51 @@ func (s *testPlanSuite) TestWindowFunction(c *C) {
}{
{
sql: "select a, avg(a) over(partition by a) from t",
result: "TableReader(Table(t))->Window(avg(cast(test.t.a)))->Projection",
result: "TableReader(Table(t))->Window(avg(cast(test.t.a)) over(partition by test.t.a))->Projection",
},
{
sql: "select a, avg(a) over(partition by b) from t",
result: "TableReader(Table(t))->Sort->Window(avg(cast(test.t.a)))->Projection",
result: "TableReader(Table(t))->Sort->Window(avg(cast(test.t.a)) over(partition by test.t.b))->Projection",
},
{
sql: "select a, avg(a+1) over(partition by (a+1)) from t",
result: "TableReader(Table(t))->Projection->Sort->Window(avg(cast(2_proj_window_3)))->Projection",
result: "TableReader(Table(t))->Projection->Sort->Window(avg(cast(2_proj_window_3)) over(partition by 2_proj_window_2))->Projection",
},
{
sql: "select a, avg(a) over(order by a asc, b desc) from t order by a asc, b desc",
result: "TableReader(Table(t))->Sort->Window(avg(cast(test.t.a)))->Projection",
result: "TableReader(Table(t))->Sort->Window(avg(cast(test.t.a)) over(order by test.t.a asc, test.t.b desc))->Projection",
},
{
sql: "select a, b as a, avg(a) over(partition by a) from t",
result: "TableReader(Table(t))->Window(avg(cast(test.t.a)))->Projection",
result: "TableReader(Table(t))->Window(avg(cast(test.t.a)) over(partition by test.t.a))->Projection",
},
{
sql: "select a, b as z, sum(z) over() from t",
result: "[planner:1054]Unknown column 'z' in 'field list'",
},
{
sql: "select a, b as z from t order by (sum(z) over())",
result: "TableReader(Table(t))->Window(sum(cast(test.t.z)))->Sort->Projection",
result: "TableReader(Table(t))->Window(sum(cast(test.t.z)) over())->Sort->Projection",
},
{
sql: "select sum(avg(a)) over() from t",
result: "TableReader(Table(t)->StreamAgg)->StreamAgg->Window(sum(sel_agg_2))->Projection",
result: "TableReader(Table(t)->StreamAgg)->StreamAgg->Window(sum(sel_agg_2) over())->Projection",
},
{
sql: "select b from t order by(sum(a) over())",
result: "TableReader(Table(t))->Window(sum(cast(test.t.a)))->Sort->Projection",
result: "TableReader(Table(t))->Window(sum(cast(test.t.a)) over())->Sort->Projection",
},
{
sql: "select b from t order by(sum(a) over(partition by a))",
result: "TableReader(Table(t))->Window(sum(cast(test.t.a)))->Sort->Projection",
result: "TableReader(Table(t))->Window(sum(cast(test.t.a)) over(partition by test.t.a))->Sort->Projection",
},
{
sql: "select b from t order by(sum(avg(a)) over())",
result: "TableReader(Table(t)->StreamAgg)->StreamAgg->Window(sum(sel_agg_2))->Sort->Projection",
result: "TableReader(Table(t)->StreamAgg)->StreamAgg->Window(sum(sel_agg_2) over())->Sort->Projection",
},
{
sql: "select a from t having (select sum(a) over() as w from t tt where a > t.a)",
result: "Apply{TableReader(Table(t))->TableReader(Table(t)->Sel([gt(tt.a, test.t.a)]))->Window(sum(cast(tt.a)))->MaxOneRow->Sel([w])}->Projection",
result: "Apply{TableReader(Table(t))->TableReader(Table(t)->Sel([gt(tt.a, test.t.a)]))->Window(sum(cast(tt.a)) over())->MaxOneRow->Sel([w])}->Projection",
},
{
sql: "select avg(a) over() as w from t having w > 1",
Expand Down Expand Up @@ -1999,11 +1999,11 @@ func (s *testPlanSuite) TestWindowFunction(c *C) {
},
{
sql: "select sum(a) over(w1), avg(a) over(w2) from t window w1 as (partition by a), w2 as (w1)",
result: "TableReader(Table(t))->Window(sum(cast(test.t.a)))->Window(avg(cast(test.t.a)))->Projection",
result: "TableReader(Table(t))->Window(sum(cast(test.t.a)) over(partition by test.t.a))->Window(avg(cast(test.t.a)) over())->Projection",
},
{
sql: "select a from t window w1 as (partition by a) order by (sum(a) over(w1))",
result: "TableReader(Table(t))->Window(sum(cast(test.t.a)))->Sort->Projection",
result: "TableReader(Table(t))->Window(sum(cast(test.t.a)) over(partition by test.t.a))->Sort->Projection",
},
{
sql: "select sum(a) over(groups 1 preceding) from t",
Expand Down
1 change: 1 addition & 0 deletions planner/core/physical_plans.go
Original file line number Diff line number Diff line change
Expand Up @@ -383,4 +383,5 @@ type PhysicalWindow struct {
WindowFuncDesc *aggregation.WindowFuncDesc
PartitionBy []property.Item
OrderBy []property.Item
Frame *WindowFrame
}
2 changes: 1 addition & 1 deletion planner/core/stringer.go
Original file line number Diff line number Diff line change
Expand Up @@ -223,7 +223,7 @@ func toString(in Plan, strs []string, idxs []int) ([]string, []int) {
case *LogicalWindow:
str = fmt.Sprintf("Window(%s)", x.WindowFuncDesc.String())
case *PhysicalWindow:
str = fmt.Sprintf("Window(%s)", x.WindowFuncDesc.String())
str = fmt.Sprintf("Window(%s)", x.ExplainInfo())
default:
str = fmt.Sprintf("%T", in)
}
Expand Down