influxdb/query/plan/physical_test.go

1118 lines
34 KiB
Go

package plan_test
import (
"math"
"testing"
"time"
"github.com/google/go-cmp/cmp"
"github.com/influxdata/platform/query"
"github.com/influxdata/platform/query/functions"
"github.com/influxdata/platform/query/plan"
"github.com/influxdata/platform/query/plan/plantest"
)
func TestPhysicalPlanner_Plan(t *testing.T) {
testCases := []struct {
name string
lp *plan.LogicalPlanSpec
pp *plan.PlanSpec
}{
{
name: "single push down",
lp: &plan.LogicalPlanSpec{
Resources: query.ResourceManagement{
ConcurrencyQuota: 1,
MemoryBytesQuota: 10000,
},
Procedures: map[plan.ProcedureID]*plan.Procedure{
plan.ProcedureIDFromOperationID("from"): {
ID: plan.ProcedureIDFromOperationID("from"),
Spec: &functions.FromProcedureSpec{
Database: "mydb",
},
Parents: nil,
Children: []plan.ProcedureID{plan.ProcedureIDFromOperationID("range")},
},
plan.ProcedureIDFromOperationID("range"): {
ID: plan.ProcedureIDFromOperationID("range"),
Spec: &functions.RangeProcedureSpec{
Bounds: plan.BoundsSpec{
Start: query.Time{
IsRelative: true,
Relative: -1 * time.Hour,
},
},
TimeCol: "_time",
},
Parents: []plan.ProcedureID{
plan.ProcedureIDFromOperationID("from"),
},
Children: []plan.ProcedureID{plan.ProcedureIDFromOperationID("count")},
},
plan.ProcedureIDFromOperationID("count"): {
ID: plan.ProcedureIDFromOperationID("count"),
Spec: &functions.CountProcedureSpec{},
Parents: []plan.ProcedureID{
(plan.ProcedureIDFromOperationID("range")),
},
Children: nil,
},
},
Order: []plan.ProcedureID{
plan.ProcedureIDFromOperationID("from"),
plan.ProcedureIDFromOperationID("range"),
plan.ProcedureIDFromOperationID("count"),
},
},
pp: &plan.PlanSpec{
Now: time.Date(2017, 8, 8, 0, 0, 0, 0, time.UTC),
Resources: query.ResourceManagement{
ConcurrencyQuota: 1,
MemoryBytesQuota: 10000,
},
Bounds: plan.BoundsSpec{
Start: query.Time{
IsRelative: true,
Relative: -1 * time.Hour,
},
},
Procedures: map[plan.ProcedureID]*plan.Procedure{
plan.ProcedureIDFromOperationID("from"): {
ID: plan.ProcedureIDFromOperationID("from"),
Spec: &functions.FromProcedureSpec{
Database: "mydb",
BoundsSet: true,
Bounds: plan.BoundsSpec{
Start: query.Time{
IsRelative: true,
Relative: -1 * time.Hour,
},
},
AggregateSet: true,
AggregateMethod: "count",
},
Parents: nil,
Children: []plan.ProcedureID{},
},
},
Results: map[string]plan.YieldSpec{
plan.DefaultYieldName: {ID: plan.ProcedureIDFromOperationID("from")},
},
Order: []plan.ProcedureID{
plan.ProcedureIDFromOperationID("from"),
},
},
},
{
name: "single push down with match",
lp: &plan.LogicalPlanSpec{
Procedures: map[plan.ProcedureID]*plan.Procedure{
plan.ProcedureIDFromOperationID("from"): {
ID: plan.ProcedureIDFromOperationID("from"),
Spec: &functions.FromProcedureSpec{
Database: "mydb",
},
Parents: nil,
Children: []plan.ProcedureID{plan.ProcedureIDFromOperationID("last")},
},
plan.ProcedureIDFromOperationID("last"): {
ID: plan.ProcedureIDFromOperationID("last"),
Spec: &functions.LastProcedureSpec{},
Parents: []plan.ProcedureID{
(plan.ProcedureIDFromOperationID("from")),
},
Children: nil,
},
},
Order: []plan.ProcedureID{
plan.ProcedureIDFromOperationID("from"),
plan.ProcedureIDFromOperationID("last"),
},
},
pp: &plan.PlanSpec{
Resources: query.ResourceManagement{
ConcurrencyQuota: 1,
MemoryBytesQuota: math.MaxInt64,
},
Now: time.Date(2017, 8, 8, 0, 0, 0, 0, time.UTC),
Bounds: plan.BoundsSpec{
Start: query.MinTime,
Stop: query.Now,
},
Procedures: map[plan.ProcedureID]*plan.Procedure{
plan.ProcedureIDFromOperationID("from"): {
ID: plan.ProcedureIDFromOperationID("from"),
Spec: &functions.FromProcedureSpec{
Database: "mydb",
BoundsSet: true,
Bounds: plan.BoundsSpec{
Start: query.MinTime,
Stop: query.Now,
},
LimitSet: true,
PointsLimit: 1,
DescendingSet: true,
Descending: true,
},
Parents: nil,
Children: []plan.ProcedureID{},
},
},
Results: map[string]plan.YieldSpec{
plan.DefaultYieldName: {ID: plan.ProcedureIDFromOperationID("from")},
},
Order: []plan.ProcedureID{
plan.ProcedureIDFromOperationID("from"),
},
},
},
{
name: "multiple push down",
lp: &plan.LogicalPlanSpec{
Procedures: map[plan.ProcedureID]*plan.Procedure{
plan.ProcedureIDFromOperationID("from"): {
ID: plan.ProcedureIDFromOperationID("from"),
Spec: &functions.FromProcedureSpec{
Database: "mydb",
},
Parents: nil,
Children: []plan.ProcedureID{plan.ProcedureIDFromOperationID("range")},
},
plan.ProcedureIDFromOperationID("range"): {
ID: plan.ProcedureIDFromOperationID("range"),
Spec: &functions.RangeProcedureSpec{
Bounds: plan.BoundsSpec{
Start: query.Time{
IsRelative: true,
Relative: -1 * time.Hour,
},
},
TimeCol: "_time",
},
Parents: []plan.ProcedureID{
(plan.ProcedureIDFromOperationID("from")),
},
Children: []plan.ProcedureID{plan.ProcedureIDFromOperationID("limit")},
},
plan.ProcedureIDFromOperationID("limit"): {
ID: plan.ProcedureIDFromOperationID("limit"),
Spec: &functions.LimitProcedureSpec{
N: 10,
},
Parents: []plan.ProcedureID{
(plan.ProcedureIDFromOperationID("range")),
},
Children: []plan.ProcedureID{plan.ProcedureIDFromOperationID("mean")},
},
plan.ProcedureIDFromOperationID("mean"): {
ID: plan.ProcedureIDFromOperationID("mean"),
Spec: &functions.MeanProcedureSpec{},
Parents: []plan.ProcedureID{
(plan.ProcedureIDFromOperationID("limit")),
},
Children: nil,
},
},
Order: []plan.ProcedureID{
plan.ProcedureIDFromOperationID("from"),
plan.ProcedureIDFromOperationID("range"),
plan.ProcedureIDFromOperationID("limit"),
plan.ProcedureIDFromOperationID("mean"),
},
},
pp: &plan.PlanSpec{
Now: time.Date(2017, 8, 8, 0, 0, 0, 0, time.UTC),
Resources: query.ResourceManagement{
ConcurrencyQuota: 2,
MemoryBytesQuota: math.MaxInt64,
},
Bounds: plan.BoundsSpec{
Start: query.Time{
IsRelative: true,
Relative: -1 * time.Hour,
},
},
Procedures: map[plan.ProcedureID]*plan.Procedure{
plan.ProcedureIDFromOperationID("from"): {
ID: plan.ProcedureIDFromOperationID("from"),
Spec: &functions.FromProcedureSpec{
Database: "mydb",
BoundsSet: true,
Bounds: plan.BoundsSpec{
Start: query.Time{
IsRelative: true,
Relative: -1 * time.Hour,
},
},
LimitSet: true,
PointsLimit: 10,
},
Parents: nil,
Children: []plan.ProcedureID{plan.ProcedureIDFromOperationID("mean")},
},
plan.ProcedureIDFromOperationID("mean"): {
ID: plan.ProcedureIDFromOperationID("mean"),
Spec: &functions.MeanProcedureSpec{},
Parents: []plan.ProcedureID{
(plan.ProcedureIDFromOperationID("from")),
},
Children: nil,
},
},
Results: map[string]plan.YieldSpec{
plan.DefaultYieldName: {ID: plan.ProcedureIDFromOperationID("mean")},
},
Order: []plan.ProcedureID{
plan.ProcedureIDFromOperationID("from"),
plan.ProcedureIDFromOperationID("mean"),
},
},
},
{
name: "multiple yield",
lp: &plan.LogicalPlanSpec{
Resources: query.ResourceManagement{
ConcurrencyQuota: 1,
MemoryBytesQuota: 10000,
},
Procedures: map[plan.ProcedureID]*plan.Procedure{
plan.ProcedureIDFromOperationID("from"): {
ID: plan.ProcedureIDFromOperationID("from"),
Spec: &functions.FromProcedureSpec{
Database: "mydb",
},
Parents: nil,
Children: []plan.ProcedureID{plan.ProcedureIDFromOperationID("range")},
},
plan.ProcedureIDFromOperationID("range"): {
ID: plan.ProcedureIDFromOperationID("range"),
Spec: &functions.RangeProcedureSpec{
Bounds: plan.BoundsSpec{
Start: query.Time{
IsRelative: true,
Relative: -1 * time.Hour,
},
},
TimeCol: "_time",
},
Parents: []plan.ProcedureID{plan.ProcedureIDFromOperationID("from")},
Children: []plan.ProcedureID{
plan.ProcedureIDFromOperationID("stddev"),
plan.ProcedureIDFromOperationID("skew"),
},
},
plan.ProcedureIDFromOperationID("stddev"): {
ID: plan.ProcedureIDFromOperationID("stddev"),
Spec: &functions.StddevProcedureSpec{},
Parents: []plan.ProcedureID{plan.ProcedureIDFromOperationID("range")},
Children: []plan.ProcedureID{plan.ProcedureIDFromOperationID("yieldStddev")},
},
plan.ProcedureIDFromOperationID("yieldStddev"): {
ID: plan.ProcedureIDFromOperationID("yieldStddev"),
Spec: &functions.YieldProcedureSpec{Name: "stddev"},
Parents: []plan.ProcedureID{plan.ProcedureIDFromOperationID("stddev")},
Children: nil,
},
plan.ProcedureIDFromOperationID("skew"): {
ID: plan.ProcedureIDFromOperationID("skew"),
Spec: &functions.SkewProcedureSpec{},
Parents: []plan.ProcedureID{plan.ProcedureIDFromOperationID("range")},
Children: []plan.ProcedureID{plan.ProcedureIDFromOperationID("yieldSkew")},
},
plan.ProcedureIDFromOperationID("yieldSkew"): {
ID: plan.ProcedureIDFromOperationID("yieldSkew"),
Spec: &functions.YieldProcedureSpec{Name: "skew"},
Parents: []plan.ProcedureID{plan.ProcedureIDFromOperationID("skew")},
Children: nil,
},
},
Order: []plan.ProcedureID{
plan.ProcedureIDFromOperationID("from"),
plan.ProcedureIDFromOperationID("range"),
plan.ProcedureIDFromOperationID("stddev"),
plan.ProcedureIDFromOperationID("yieldStddev"),
plan.ProcedureIDFromOperationID("skew"),
plan.ProcedureIDFromOperationID("yieldSkew"),
},
},
pp: &plan.PlanSpec{
Now: time.Date(2017, 8, 8, 0, 0, 0, 0, time.UTC),
Resources: query.ResourceManagement{
ConcurrencyQuota: 1,
MemoryBytesQuota: 10000,
},
Bounds: plan.BoundsSpec{
Start: query.Time{
IsRelative: true,
Relative: -1 * time.Hour,
},
},
Procedures: map[plan.ProcedureID]*plan.Procedure{
plan.ProcedureIDFromOperationID("from"): {
ID: plan.ProcedureIDFromOperationID("from"),
Spec: &functions.FromProcedureSpec{
Database: "mydb",
BoundsSet: true,
Bounds: plan.BoundsSpec{
Start: query.Time{
IsRelative: true,
Relative: -1 * time.Hour,
},
},
},
Parents: nil,
Children: []plan.ProcedureID{
plan.ProcedureIDFromOperationID("stddev"),
plan.ProcedureIDFromOperationID("skew"),
},
},
plan.ProcedureIDFromOperationID("stddev"): {
ID: plan.ProcedureIDFromOperationID("stddev"),
Spec: &functions.StddevProcedureSpec{},
Parents: []plan.ProcedureID{plan.ProcedureIDFromOperationID("from")},
Children: []plan.ProcedureID{},
},
plan.ProcedureIDFromOperationID("skew"): {
ID: plan.ProcedureIDFromOperationID("skew"),
Spec: &functions.SkewProcedureSpec{},
Parents: []plan.ProcedureID{plan.ProcedureIDFromOperationID("from")},
Children: []plan.ProcedureID{},
},
},
Results: map[string]plan.YieldSpec{
"stddev": {ID: plan.ProcedureIDFromOperationID("stddev")},
"skew": {ID: plan.ProcedureIDFromOperationID("skew")},
},
Order: []plan.ProcedureID{
plan.ProcedureIDFromOperationID("from"),
plan.ProcedureIDFromOperationID("stddev"),
plan.ProcedureIDFromOperationID("skew"),
},
},
},
{
name: "group with aggregate",
lp: &plan.LogicalPlanSpec{
Resources: query.ResourceManagement{
ConcurrencyQuota: 1,
MemoryBytesQuota: 10000,
},
Procedures: map[plan.ProcedureID]*plan.Procedure{
plan.ProcedureIDFromOperationID("from"): {
ID: plan.ProcedureIDFromOperationID("from"),
Spec: &functions.FromProcedureSpec{
Database: "mydb",
},
Parents: nil,
Children: []plan.ProcedureID{plan.ProcedureIDFromOperationID("range")},
},
plan.ProcedureIDFromOperationID("range"): {
ID: plan.ProcedureIDFromOperationID("range"),
Spec: &functions.RangeProcedureSpec{
Bounds: plan.BoundsSpec{
Start: query.Time{
IsRelative: true,
Relative: -1 * time.Hour,
},
},
TimeCol: "_time",
},
Parents: []plan.ProcedureID{plan.ProcedureIDFromOperationID("from")},
Children: []plan.ProcedureID{
plan.ProcedureIDFromOperationID("group"),
},
},
plan.ProcedureIDFromOperationID("group"): {
ID: plan.ProcedureIDFromOperationID("group"),
Spec: &functions.GroupProcedureSpec{
GroupMode: functions.GroupModeBy,
GroupKeys: []string{"host", "region"},
},
Parents: []plan.ProcedureID{plan.ProcedureIDFromOperationID("range")},
Children: []plan.ProcedureID{plan.ProcedureIDFromOperationID("sum")},
},
plan.ProcedureIDFromOperationID("sum"): {
ID: plan.ProcedureIDFromOperationID("sum"),
Spec: &functions.SumProcedureSpec{},
Parents: []plan.ProcedureID{plan.ProcedureIDFromOperationID("group")},
},
},
Order: []plan.ProcedureID{
plan.ProcedureIDFromOperationID("from"),
plan.ProcedureIDFromOperationID("range"),
plan.ProcedureIDFromOperationID("group"),
plan.ProcedureIDFromOperationID("sum"),
},
},
pp: &plan.PlanSpec{
Now: time.Date(2017, 8, 8, 0, 0, 0, 0, time.UTC),
Resources: query.ResourceManagement{
ConcurrencyQuota: 1,
MemoryBytesQuota: 10000,
},
Bounds: plan.BoundsSpec{
Start: query.Time{
IsRelative: true,
Relative: -1 * time.Hour,
},
},
Procedures: map[plan.ProcedureID]*plan.Procedure{
plan.ProcedureIDFromOperationID("from"): {
ID: plan.ProcedureIDFromOperationID("from"),
Spec: &functions.FromProcedureSpec{
Database: "mydb",
BoundsSet: true,
Bounds: plan.BoundsSpec{
Start: query.Time{
IsRelative: true,
Relative: -1 * time.Hour,
},
},
GroupingSet: true,
GroupMode: functions.GroupModeBy,
GroupKeys: []string{"host", "region"},
AggregateSet: true,
AggregateMethod: "sum",
},
Parents: nil,
Children: []plan.ProcedureID{
plan.ProcedureIDFromParentID(plan.ProcedureIDFromOperationID("from")),
},
},
plan.ProcedureIDFromParentID(plan.ProcedureIDFromOperationID("from")): {
ID: plan.ProcedureIDFromParentID(plan.ProcedureIDFromOperationID("from")),
Spec: &functions.SumProcedureSpec{},
Parents: []plan.ProcedureID{plan.ProcedureIDFromOperationID("from")},
},
},
Results: map[string]plan.YieldSpec{
"_result": {ID: plan.ProcedureIDFromParentID(plan.ProcedureIDFromOperationID("from"))},
},
Order: []plan.ProcedureID{
plan.ProcedureIDFromOperationID("from"),
plan.ProcedureIDFromParentID(plan.ProcedureIDFromOperationID("from")),
},
},
},
{
name: "group with distinct on tag",
lp: &plan.LogicalPlanSpec{
Resources: query.ResourceManagement{
ConcurrencyQuota: 1,
MemoryBytesQuota: 10000,
},
Procedures: map[plan.ProcedureID]*plan.Procedure{
plan.ProcedureIDFromOperationID("from"): {
ID: plan.ProcedureIDFromOperationID("from"),
Spec: &functions.FromProcedureSpec{
Database: "mydb",
},
Parents: nil,
Children: []plan.ProcedureID{plan.ProcedureIDFromOperationID("range")},
},
plan.ProcedureIDFromOperationID("range"): {
ID: plan.ProcedureIDFromOperationID("range"),
Spec: &functions.RangeProcedureSpec{
Bounds: plan.BoundsSpec{
Start: query.Time{
IsRelative: true,
Relative: -1 * time.Hour,
},
},
TimeCol: "_time",
},
Parents: []plan.ProcedureID{plan.ProcedureIDFromOperationID("from")},
Children: []plan.ProcedureID{
plan.ProcedureIDFromOperationID("group"),
},
},
plan.ProcedureIDFromOperationID("group"): {
ID: plan.ProcedureIDFromOperationID("group"),
Spec: &functions.GroupProcedureSpec{
GroupMode: functions.GroupModeBy,
GroupKeys: []string{"host"},
},
Parents: []plan.ProcedureID{plan.ProcedureIDFromOperationID("range")},
Children: []plan.ProcedureID{plan.ProcedureIDFromOperationID("distinct")},
},
plan.ProcedureIDFromOperationID("distinct"): {
ID: plan.ProcedureIDFromOperationID("distinct"),
Spec: &functions.DistinctProcedureSpec{
Column: "host",
},
Parents: []plan.ProcedureID{plan.ProcedureIDFromOperationID("group")},
},
},
Order: []plan.ProcedureID{
plan.ProcedureIDFromOperationID("from"),
plan.ProcedureIDFromOperationID("range"),
plan.ProcedureIDFromOperationID("group"),
plan.ProcedureIDFromOperationID("distinct"),
},
},
pp: &plan.PlanSpec{
Now: time.Date(2017, 8, 8, 0, 0, 0, 0, time.UTC),
Resources: query.ResourceManagement{
ConcurrencyQuota: 1,
MemoryBytesQuota: 10000,
},
Bounds: plan.BoundsSpec{
Start: query.Time{
IsRelative: true,
Relative: -1 * time.Hour,
},
},
Procedures: map[plan.ProcedureID]*plan.Procedure{
plan.ProcedureIDFromOperationID("from"): {
ID: plan.ProcedureIDFromOperationID("from"),
Spec: &functions.FromProcedureSpec{
Database: "mydb",
BoundsSet: true,
Bounds: plan.BoundsSpec{
Start: query.Time{
IsRelative: true,
Relative: -1 * time.Hour,
},
},
GroupingSet: true,
GroupMode: functions.GroupModeBy,
GroupKeys: []string{"host"},
LimitSet: true,
PointsLimit: -1,
},
Parents: nil,
Children: []plan.ProcedureID{
plan.ProcedureIDFromOperationID("distinct"),
},
},
plan.ProcedureIDFromOperationID("distinct"): {
ID: plan.ProcedureIDFromOperationID("distinct"),
Spec: &functions.DistinctProcedureSpec{Column: "host"},
Parents: []plan.ProcedureID{plan.ProcedureIDFromOperationID("from")},
},
},
Results: map[string]plan.YieldSpec{
"_result": {ID: plan.ProcedureIDFromOperationID("distinct")},
},
Order: []plan.ProcedureID{
plan.ProcedureIDFromOperationID("from"),
plan.ProcedureIDFromOperationID("distinct"),
},
},
},
{
name: "group with distinct on _value does not optimize",
lp: &plan.LogicalPlanSpec{
Resources: query.ResourceManagement{
ConcurrencyQuota: 1,
MemoryBytesQuota: 10000,
},
Procedures: map[plan.ProcedureID]*plan.Procedure{
plan.ProcedureIDFromOperationID("from"): {
ID: plan.ProcedureIDFromOperationID("from"),
Spec: &functions.FromProcedureSpec{
Database: "mydb",
},
Parents: nil,
Children: []plan.ProcedureID{plan.ProcedureIDFromOperationID("range")},
},
plan.ProcedureIDFromOperationID("range"): {
ID: plan.ProcedureIDFromOperationID("range"),
Spec: &functions.RangeProcedureSpec{
Bounds: plan.BoundsSpec{
Start: query.Time{
IsRelative: true,
Relative: -1 * time.Hour,
},
},
TimeCol: "_time",
},
Parents: []plan.ProcedureID{plan.ProcedureIDFromOperationID("from")},
Children: []plan.ProcedureID{
plan.ProcedureIDFromOperationID("group"),
},
},
plan.ProcedureIDFromOperationID("group"): {
ID: plan.ProcedureIDFromOperationID("group"),
Spec: &functions.GroupProcedureSpec{
GroupMode: functions.GroupModeBy,
GroupKeys: []string{"host"},
},
Parents: []plan.ProcedureID{plan.ProcedureIDFromOperationID("range")},
Children: []plan.ProcedureID{plan.ProcedureIDFromOperationID("distinct")},
},
plan.ProcedureIDFromOperationID("distinct"): {
ID: plan.ProcedureIDFromOperationID("distinct"),
Spec: &functions.DistinctProcedureSpec{
Column: "_value",
},
Parents: []plan.ProcedureID{plan.ProcedureIDFromOperationID("group")},
},
},
Order: []plan.ProcedureID{
plan.ProcedureIDFromOperationID("from"),
plan.ProcedureIDFromOperationID("range"),
plan.ProcedureIDFromOperationID("group"),
plan.ProcedureIDFromOperationID("distinct"),
},
},
pp: &plan.PlanSpec{
Now: time.Date(2017, 8, 8, 0, 0, 0, 0, time.UTC),
Resources: query.ResourceManagement{
ConcurrencyQuota: 1,
MemoryBytesQuota: 10000,
},
Bounds: plan.BoundsSpec{
Start: query.Time{
IsRelative: true,
Relative: -1 * time.Hour,
},
},
Procedures: map[plan.ProcedureID]*plan.Procedure{
plan.ProcedureIDFromOperationID("from"): {
ID: plan.ProcedureIDFromOperationID("from"),
Spec: &functions.FromProcedureSpec{
Database: "mydb",
BoundsSet: true,
Bounds: plan.BoundsSpec{
Start: query.Time{
IsRelative: true,
Relative: -1 * time.Hour,
},
},
GroupingSet: true,
GroupMode: functions.GroupModeBy,
GroupKeys: []string{"host"},
},
Parents: nil,
Children: []plan.ProcedureID{
plan.ProcedureIDFromOperationID("distinct"),
},
},
plan.ProcedureIDFromOperationID("distinct"): {
ID: plan.ProcedureIDFromOperationID("distinct"),
Spec: &functions.DistinctProcedureSpec{Column: "_value"},
Parents: []plan.ProcedureID{plan.ProcedureIDFromOperationID("from")},
},
},
Results: map[string]plan.YieldSpec{
"_result": {ID: plan.ProcedureIDFromOperationID("distinct")},
},
Order: []plan.ProcedureID{
plan.ProcedureIDFromOperationID("from"),
plan.ProcedureIDFromOperationID("distinct"),
},
},
},
{
name: "group with distinct on non-grouped does not optimize",
lp: &plan.LogicalPlanSpec{
Resources: query.ResourceManagement{
ConcurrencyQuota: 1,
MemoryBytesQuota: 10000,
},
Procedures: map[plan.ProcedureID]*plan.Procedure{
plan.ProcedureIDFromOperationID("from"): {
ID: plan.ProcedureIDFromOperationID("from"),
Spec: &functions.FromProcedureSpec{
Database: "mydb",
},
Parents: nil,
Children: []plan.ProcedureID{plan.ProcedureIDFromOperationID("range")},
},
plan.ProcedureIDFromOperationID("range"): {
ID: plan.ProcedureIDFromOperationID("range"),
Spec: &functions.RangeProcedureSpec{
Bounds: plan.BoundsSpec{
Start: query.Time{
IsRelative: true,
Relative: -1 * time.Hour,
},
},
TimeCol: "_time",
},
Parents: []plan.ProcedureID{plan.ProcedureIDFromOperationID("from")},
Children: []plan.ProcedureID{
plan.ProcedureIDFromOperationID("group"),
},
},
plan.ProcedureIDFromOperationID("group"): {
ID: plan.ProcedureIDFromOperationID("group"),
Spec: &functions.GroupProcedureSpec{
GroupMode: functions.GroupModeBy,
GroupKeys: []string{"host"},
},
Parents: []plan.ProcedureID{plan.ProcedureIDFromOperationID("range")},
Children: []plan.ProcedureID{plan.ProcedureIDFromOperationID("distinct")},
},
plan.ProcedureIDFromOperationID("distinct"): {
ID: plan.ProcedureIDFromOperationID("distinct"),
Spec: &functions.DistinctProcedureSpec{
Column: "region",
},
Parents: []plan.ProcedureID{plan.ProcedureIDFromOperationID("group")},
},
},
Order: []plan.ProcedureID{
plan.ProcedureIDFromOperationID("from"),
plan.ProcedureIDFromOperationID("range"),
plan.ProcedureIDFromOperationID("group"),
plan.ProcedureIDFromOperationID("distinct"),
},
},
pp: &plan.PlanSpec{
Now: time.Date(2017, 8, 8, 0, 0, 0, 0, time.UTC),
Resources: query.ResourceManagement{
ConcurrencyQuota: 1,
MemoryBytesQuota: 10000,
},
Bounds: plan.BoundsSpec{
Start: query.Time{
IsRelative: true,
Relative: -1 * time.Hour,
},
},
Procedures: map[plan.ProcedureID]*plan.Procedure{
plan.ProcedureIDFromOperationID("from"): {
ID: plan.ProcedureIDFromOperationID("from"),
Spec: &functions.FromProcedureSpec{
Database: "mydb",
BoundsSet: true,
Bounds: plan.BoundsSpec{
Start: query.Time{
IsRelative: true,
Relative: -1 * time.Hour,
},
},
GroupingSet: true,
GroupMode: functions.GroupModeBy,
GroupKeys: []string{"host"},
},
Parents: nil,
Children: []plan.ProcedureID{
plan.ProcedureIDFromOperationID("distinct"),
},
},
plan.ProcedureIDFromOperationID("distinct"): {
ID: plan.ProcedureIDFromOperationID("distinct"),
Spec: &functions.DistinctProcedureSpec{Column: "region"},
Parents: []plan.ProcedureID{plan.ProcedureIDFromOperationID("from")},
},
},
Results: map[string]plan.YieldSpec{
"_result": {ID: plan.ProcedureIDFromOperationID("distinct")},
},
Order: []plan.ProcedureID{
plan.ProcedureIDFromOperationID("from"),
plan.ProcedureIDFromOperationID("distinct"),
},
},
},
}
for _, tc := range testCases {
tc := tc
t.Run(tc.name, func(t *testing.T) {
PhysicalPlanTestHelper(t, tc.lp, tc.pp)
})
}
}
func TestPhysicalPlanner_Plan_PushDown_Branch(t *testing.T) {
lp := &plan.LogicalPlanSpec{
Procedures: map[plan.ProcedureID]*plan.Procedure{
plan.ProcedureIDFromOperationID("from"): {
ID: plan.ProcedureIDFromOperationID("from"),
Spec: &functions.FromProcedureSpec{
Database: "mydb",
},
Parents: nil,
Children: []plan.ProcedureID{
plan.ProcedureIDFromOperationID("first"),
plan.ProcedureIDFromOperationID("last"),
},
},
plan.ProcedureIDFromOperationID("first"): {
ID: plan.ProcedureIDFromOperationID("first"),
Spec: &functions.FirstProcedureSpec{},
Parents: []plan.ProcedureID{plan.ProcedureIDFromOperationID("from")},
Children: []plan.ProcedureID{plan.ProcedureIDFromOperationID("yieldFirst")},
},
plan.ProcedureIDFromOperationID("yieldFirst"): {
ID: plan.ProcedureIDFromOperationID("yieldFirst"),
Spec: &functions.YieldProcedureSpec{Name: "first"},
Parents: []plan.ProcedureID{plan.ProcedureIDFromOperationID("first")},
Children: nil,
},
plan.ProcedureIDFromOperationID("last"): {
ID: plan.ProcedureIDFromOperationID("last"),
Spec: &functions.LastProcedureSpec{},
Parents: []plan.ProcedureID{plan.ProcedureIDFromOperationID("from")},
Children: []plan.ProcedureID{plan.ProcedureIDFromOperationID("yieldLast")},
},
plan.ProcedureIDFromOperationID("yieldLast"): {
ID: plan.ProcedureIDFromOperationID("yieldLast"),
Spec: &functions.YieldProcedureSpec{Name: "last"},
Parents: []plan.ProcedureID{plan.ProcedureIDFromOperationID("last")},
Children: nil,
},
},
Order: []plan.ProcedureID{
plan.ProcedureIDFromOperationID("from"),
plan.ProcedureIDFromOperationID("first"),
plan.ProcedureIDFromOperationID("yieldFirst"),
plan.ProcedureIDFromOperationID("last"), // last is last so it will be duplicated
plan.ProcedureIDFromOperationID("yieldLast"),
},
}
fromID := plan.ProcedureIDFromOperationID("from")
fromIDDup := plan.ProcedureIDForDuplicate(fromID)
want := &plan.PlanSpec{
Bounds: plan.BoundsSpec{
Start: query.MinTime,
Stop: query.Now,
},
Resources: query.ResourceManagement{
ConcurrencyQuota: 2,
MemoryBytesQuota: math.MaxInt64,
},
Procedures: map[plan.ProcedureID]*plan.Procedure{
fromID: {
ID: fromID,
Spec: &functions.FromProcedureSpec{
Database: "mydb",
BoundsSet: true,
Bounds: plan.BoundsSpec{
Start: query.MinTime,
Stop: query.Now,
},
LimitSet: true,
PointsLimit: 1,
DescendingSet: true,
Descending: true, // last
},
Children: []plan.ProcedureID{},
},
fromIDDup: {
ID: fromIDDup,
Spec: &functions.FromProcedureSpec{
Database: "mydb",
BoundsSet: true,
Bounds: plan.BoundsSpec{
Start: query.MinTime,
Stop: query.Now,
},
LimitSet: true,
PointsLimit: 1,
DescendingSet: true,
Descending: false, // first
},
Parents: []plan.ProcedureID{},
Children: []plan.ProcedureID{},
},
},
Results: map[string]plan.YieldSpec{
"first": {ID: fromIDDup},
"last": {ID: fromID},
},
Order: []plan.ProcedureID{
fromID,
fromIDDup,
},
}
PhysicalPlanTestHelper(t, lp, want)
}
func TestPhysicalPlanner_Plan_PushDown_Mixed(t *testing.T) {
lp := &plan.LogicalPlanSpec{
Procedures: map[plan.ProcedureID]*plan.Procedure{
plan.ProcedureIDFromOperationID("from"): {
ID: plan.ProcedureIDFromOperationID("from"),
Spec: &functions.FromProcedureSpec{
Database: "mydb",
},
Parents: nil,
Children: []plan.ProcedureID{plan.ProcedureIDFromOperationID("range")},
},
plan.ProcedureIDFromOperationID("range"): {
ID: plan.ProcedureIDFromOperationID("range"),
Spec: &functions.RangeProcedureSpec{
Bounds: plan.BoundsSpec{
Start: query.Time{
IsRelative: true,
Relative: -1 * time.Hour,
},
},
TimeCol: "_time",
},
Parents: []plan.ProcedureID{
(plan.ProcedureIDFromOperationID("from")),
},
Children: []plan.ProcedureID{
plan.ProcedureIDFromOperationID("sum"),
plan.ProcedureIDFromOperationID("mean"),
},
},
plan.ProcedureIDFromOperationID("sum"): {
ID: plan.ProcedureIDFromOperationID("sum"),
Spec: &functions.SumProcedureSpec{},
Parents: []plan.ProcedureID{plan.ProcedureIDFromOperationID("range")},
Children: []plan.ProcedureID{plan.ProcedureIDFromOperationID("yieldSum")},
},
plan.ProcedureIDFromOperationID("yieldSum"): {
ID: plan.ProcedureIDFromOperationID("yieldSum"),
Spec: &functions.YieldProcedureSpec{Name: "sum"},
Parents: []plan.ProcedureID{plan.ProcedureIDFromOperationID("sum")},
Children: nil,
},
plan.ProcedureIDFromOperationID("mean"): {
ID: plan.ProcedureIDFromOperationID("mean"),
Spec: &functions.MeanProcedureSpec{},
Parents: []plan.ProcedureID{plan.ProcedureIDFromOperationID("range")},
Children: []plan.ProcedureID{plan.ProcedureIDFromOperationID("yieldMean")},
},
plan.ProcedureIDFromOperationID("yieldMean"): {
ID: plan.ProcedureIDFromOperationID("yieldMean"),
Spec: &functions.YieldProcedureSpec{Name: "mean"},
Parents: []plan.ProcedureID{plan.ProcedureIDFromOperationID("mean")},
Children: nil,
},
},
Order: []plan.ProcedureID{
plan.ProcedureIDFromOperationID("from"),
plan.ProcedureIDFromOperationID("range"),
plan.ProcedureIDFromOperationID("sum"),
plan.ProcedureIDFromOperationID("yieldSum"),
plan.ProcedureIDFromOperationID("mean"), // Mean can't be pushed down, but sum can
plan.ProcedureIDFromOperationID("yieldMean"),
},
}
fromID := plan.ProcedureIDFromOperationID("from")
fromIDDup := plan.ProcedureIDForDuplicate(fromID)
want := &plan.PlanSpec{
Bounds: plan.BoundsSpec{
Start: query.Time{
IsRelative: true,
Relative: -1 * time.Hour,
},
},
Resources: query.ResourceManagement{
ConcurrencyQuota: 3,
MemoryBytesQuota: math.MaxInt64,
},
Procedures: map[plan.ProcedureID]*plan.Procedure{
fromIDDup: {
ID: fromIDDup,
Spec: &functions.FromProcedureSpec{
Database: "mydb",
BoundsSet: true,
Bounds: plan.BoundsSpec{
Start: query.Time{
IsRelative: true,
Relative: -1 * time.Hour,
},
},
AggregateSet: true,
AggregateMethod: "sum",
},
Parents: []plan.ProcedureID{},
Children: []plan.ProcedureID{},
},
plan.ProcedureIDFromOperationID("from"): {
ID: plan.ProcedureIDFromOperationID("from"),
Spec: &functions.FromProcedureSpec{
Database: "mydb",
BoundsSet: true,
Bounds: plan.BoundsSpec{
Start: query.Time{
IsRelative: true,
Relative: -1 * time.Hour,
},
},
},
Children: []plan.ProcedureID{plan.ProcedureIDFromOperationID("mean")},
},
plan.ProcedureIDFromOperationID("mean"): {
ID: plan.ProcedureIDFromOperationID("mean"),
Spec: &functions.MeanProcedureSpec{},
Parents: []plan.ProcedureID{plan.ProcedureIDFromOperationID("from")},
Children: []plan.ProcedureID{},
},
},
Results: map[string]plan.YieldSpec{
"sum": {ID: fromIDDup},
"mean": {ID: plan.ProcedureIDFromOperationID("mean")},
},
Order: []plan.ProcedureID{
fromID,
fromIDDup,
plan.ProcedureIDFromOperationID("mean"),
},
}
PhysicalPlanTestHelper(t, lp, want)
}
func PhysicalPlanTestHelper(t *testing.T, lp *plan.LogicalPlanSpec, want *plan.PlanSpec) {
t.Helper()
// Setup expected now time
now := time.Now()
lp.Now = now
want.Now = now
planner := plan.NewPlanner()
got, err := planner.Plan(lp, nil)
if err != nil {
t.Fatal(err)
}
if !cmp.Equal(got, want, plantest.CmpOptions...) {
t.Log("Logical:", plan.Formatted(lp))
t.Log("Want Physical:", plan.Formatted(want))
t.Log("Got Physical:", plan.Formatted(got))
t.Errorf("unexpected physical plan -want/+got:\n%s", cmp.Diff(want, got, plantest.CmpOptions...))
}
}
var benchmarkPhysicalPlan *plan.PlanSpec
func BenchmarkPhysicalPlan(b *testing.B) {
var err error
lp, err := plan.NewLogicalPlanner().Plan(benchmarkQuery)
if err != nil {
b.Fatal(err)
}
now := time.Date(2017, 8, 8, 0, 0, 0, 0, time.UTC)
lp.Now = now
planner := plan.NewPlanner()
for n := 0; n < b.N; n++ {
benchmarkPhysicalPlan, err = planner.Plan(lp, nil)
if err != nil {
b.Fatal(err)
}
}
}
var benchmarkQueryToPhysicalPlan *plan.PlanSpec
func BenchmarkQueryToPhysicalPlan(b *testing.B) {
lp := plan.NewLogicalPlanner()
pp := plan.NewPlanner()
now := time.Date(2017, 8, 8, 0, 0, 0, 0, time.UTC)
for n := 0; n < b.N; n++ {
lp, err := lp.Plan(benchmarkQuery)
if err != nil {
b.Fatal(err)
}
lp.Now = now
benchmarkQueryToPhysicalPlan, err = pp.Plan(lp, nil)
if err != nil {
b.Fatal(err)
}
}
}