зеркало из https://github.com/github/vitess-gh.git
Merge subqueries that "join" on lookup index columns. (#10966)
* Improved logic for subquery merging This is a squash of a number of commits created by Arthur. Co-authored-by: Arthur Schreiber <arthurschreiber@github.com> Signed-off-by: Andres Taylor <andres@planetscale.com> * refactor: use existing functionality in ExtractedSubquery Signed-off-by: Andres Taylor <andres@planetscale.com> * refactor: extract the ColName only once Signed-off-by: Andres Taylor <andres@planetscale.com> * comments Signed-off-by: Andres Taylor <andres@planetscale.com> * turn off linter that is wrong Signed-off-by: Andres Taylor <andres@planetscale.com> * cleanup and commenting Signed-off-by: Andres Taylor <andres@planetscale.com> * refactor and comments Signed-off-by: Andres Taylor <andres@planetscale.com> Signed-off-by: Andres Taylor <andres@planetscale.com> Co-authored-by: Andres Taylor <andres@planetscale.com>
This commit is contained in:
Родитель
8037f43d00
Коммит
e17b4e16f9
|
@ -118,41 +118,5 @@ func (d *Derived) findOutputColumn(name *sqlparser.ColName) (int, error) {
|
|||
// Since vtgate joins are always nested loop joins, we can't execute them on the RHS
|
||||
// if they do some things, like LIMIT or GROUP BY on wrong columns
|
||||
func (d *Derived) IsMergeable(ctx *plancontext.PlanningContext) bool {
|
||||
validVindex := func(expr sqlparser.Expr) bool {
|
||||
sc := findColumnVindex(ctx, d, expr)
|
||||
return sc != nil && sc.IsUnique()
|
||||
}
|
||||
|
||||
if d.Query.GetLimit() != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
sel, ok := d.Query.(*sqlparser.Select)
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
|
||||
if len(sel.GroupBy) > 0 {
|
||||
// iff we are grouping, we need to check that we can perform the grouping inside a single shard, and we check that
|
||||
// by checking that one of the grouping expressions used is a unique single column vindex.
|
||||
// TODO: we could also support the case where all the columns of a multi-column vindex are used in the grouping
|
||||
for _, gb := range sel.GroupBy {
|
||||
if validVindex(gb) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// if we have grouping, we have already checked that it's safe, and don't need to check for aggregations
|
||||
// but if we don't have groupings, we need to check if there are aggregations that will mess with us
|
||||
if sqlparser.ContainsAggregation(sel.SelectExprs) {
|
||||
return false
|
||||
}
|
||||
|
||||
if sqlparser.ContainsAggregation(sel.Having) {
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
return isMergeable(ctx, d.Query, d)
|
||||
}
|
||||
|
|
|
@ -639,6 +639,8 @@ func getJoinFor(ctx *plancontext.PlanningContext, cm opCacheMap, lhs, rhs abstra
|
|||
return join, nil
|
||||
}
|
||||
|
||||
// requiresSwitchingSides will return true if any of the operators with the root from the given operator tree
|
||||
// is of the type that should not be on the RHS of a join
|
||||
func requiresSwitchingSides(ctx *plancontext.PlanningContext, op abstract.PhysicalOperator) bool {
|
||||
required := false
|
||||
|
||||
|
@ -792,6 +794,7 @@ func tryMerge(
|
|||
// no join predicates - no vindex
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
if !sameKeyspace {
|
||||
return nil, vterrors.New(vtrpcpb.Code_UNIMPLEMENTED, "unsupported: cross-shard correlated subquery")
|
||||
}
|
||||
|
@ -925,6 +928,11 @@ func findColumnVindex(ctx *plancontext.PlanningContext, a abstract.PhysicalOpera
|
|||
return nil
|
||||
}
|
||||
|
||||
exp = unwrapDerivedTables(ctx, exp)
|
||||
if exp == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
var singCol vindexes.SingleColumn
|
||||
|
||||
// for each equality expression that exp has with other column name, we check if it
|
||||
|
@ -936,14 +944,15 @@ func findColumnVindex(ctx *plancontext.PlanningContext, a abstract.PhysicalOpera
|
|||
if !isCol {
|
||||
continue
|
||||
}
|
||||
leftDep := ctx.SemTable.RecursiveDeps(expr)
|
||||
|
||||
deps := ctx.SemTable.RecursiveDeps(expr)
|
||||
|
||||
_ = VisitOperators(a, func(rel abstract.PhysicalOperator) (bool, error) {
|
||||
to, isTableOp := rel.(abstract.IntroducesTable)
|
||||
if !isTableOp {
|
||||
return true, nil
|
||||
}
|
||||
if leftDep.IsSolvedBy(to.GetQTable().ID) {
|
||||
if deps.IsSolvedBy(to.GetQTable().ID) {
|
||||
for _, vindex := range to.GetVTable().ColumnVindexes {
|
||||
sC, isSingle := vindex.Vindex.(vindexes.SingleColumn)
|
||||
if isSingle && vindex.Columns[0].Equal(col.Name) {
|
||||
|
@ -962,6 +971,47 @@ func findColumnVindex(ctx *plancontext.PlanningContext, a abstract.PhysicalOpera
|
|||
return singCol
|
||||
}
|
||||
|
||||
// unwrapDerivedTables we want to find the bottom layer of derived tables
|
||||
// nolint
|
||||
func unwrapDerivedTables(ctx *plancontext.PlanningContext, exp sqlparser.Expr) sqlparser.Expr {
|
||||
for {
|
||||
// if we are dealing with derived tables in derived tables
|
||||
tbl, err := ctx.SemTable.TableInfoForExpr(exp)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
_, ok := tbl.(*semantics.DerivedTable)
|
||||
if !ok {
|
||||
break
|
||||
}
|
||||
|
||||
exp, err = semantics.RewriteDerivedTableExpression(exp, tbl)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
exp = getColName(exp)
|
||||
if exp == nil {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
return exp
|
||||
}
|
||||
|
||||
func getColName(exp sqlparser.Expr) *sqlparser.ColName {
|
||||
switch exp := exp.(type) {
|
||||
case *sqlparser.ColName:
|
||||
return exp
|
||||
case *sqlparser.Max, *sqlparser.Min:
|
||||
aggr := exp.(sqlparser.AggrFunc).GetArg()
|
||||
colName, ok := aggr.(*sqlparser.ColName)
|
||||
if ok {
|
||||
return colName
|
||||
}
|
||||
}
|
||||
// for any other expression than a column, or the extremum of a column, we return nil
|
||||
return nil
|
||||
}
|
||||
|
||||
func canMergeOnFilters(ctx *plancontext.PlanningContext, a, b *Route, joinPredicates []sqlparser.Expr) bool {
|
||||
for _, predicate := range joinPredicates {
|
||||
for _, expr := range sqlparser.SplitAndExpression(nil, predicate) {
|
||||
|
|
|
@ -113,10 +113,13 @@ func mergeSubQueryOp(ctx *plancontext.PlanningContext, outer *Route, inner *Rout
|
|||
//
|
||||
// Note that not all inner queries necessarily are part of the routing
|
||||
// predicates list, so this might be a no-op.
|
||||
subQueryWasPredicate := false
|
||||
for i, predicate := range outer.SeenPredicates {
|
||||
if sqlparser.EqualsExpr(predicate, subq.ExtractedSubquery) {
|
||||
outer.SeenPredicates = append(outer.SeenPredicates[:i], outer.SeenPredicates[i+1:]...)
|
||||
|
||||
subQueryWasPredicate = true
|
||||
|
||||
// The `ExtractedSubquery` of an inner query is unique (due to the uniqueness of bind variable names)
|
||||
// so we can stop after the first match.
|
||||
break
|
||||
|
@ -127,9 +130,60 @@ func mergeSubQueryOp(ctx *plancontext.PlanningContext, outer *Route, inner *Rout
|
|||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if subQueryWasPredicate {
|
||||
// Copy Vindex predicates from the inner route to the upper route.
|
||||
// If we can route based on some of these predicates, the routing can improve
|
||||
outer.VindexPreds = append(outer.VindexPreds, inner.VindexPreds...)
|
||||
|
||||
if inner.RouteOpCode == engine.None {
|
||||
outer.setSelectNoneOpcode()
|
||||
}
|
||||
}
|
||||
|
||||
return outer, nil
|
||||
}
|
||||
|
||||
func isMergeable(ctx *plancontext.PlanningContext, query sqlparser.SelectStatement, op abstract.PhysicalOperator) bool {
|
||||
validVindex := func(expr sqlparser.Expr) bool {
|
||||
sc := findColumnVindex(ctx, op, expr)
|
||||
return sc != nil && sc.IsUnique()
|
||||
}
|
||||
|
||||
if query.GetLimit() != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
sel, ok := query.(*sqlparser.Select)
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
|
||||
if len(sel.GroupBy) > 0 {
|
||||
// iff we are grouping, we need to check that we can perform the grouping inside a single shard, and we check that
|
||||
// by checking that one of the grouping expressions used is a unique single column vindex.
|
||||
// TODO: we could also support the case where all the columns of a multi-column vindex are used in the grouping
|
||||
for _, gb := range sel.GroupBy {
|
||||
if validVindex(gb) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// if we have grouping, we have already checked that it's safe, and don't need to check for aggregations
|
||||
// but if we don't have groupings, we need to check if there are aggregations that will mess with us
|
||||
if sqlparser.ContainsAggregation(sel.SelectExprs) {
|
||||
return false
|
||||
}
|
||||
|
||||
if sqlparser.ContainsAggregation(sel.Having) {
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
func tryMergeSubQueryOp(
|
||||
ctx *plancontext.PlanningContext,
|
||||
outer, subq abstract.PhysicalOperator,
|
||||
|
@ -137,84 +191,129 @@ func tryMergeSubQueryOp(
|
|||
joinPredicates []sqlparser.Expr,
|
||||
merger mergeFunc,
|
||||
) (abstract.PhysicalOperator, error) {
|
||||
var merged abstract.PhysicalOperator
|
||||
var err error
|
||||
switch outerOp := outer.(type) {
|
||||
case *Route:
|
||||
if shouldTryMergingSubquery(outerOp, subq) {
|
||||
merged, err = tryMerge(ctx, outerOp, subq, joinPredicates, merger)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return merged, err
|
||||
}
|
||||
return nil, nil
|
||||
return tryMergeSubqueryWithRoute(ctx, subq, outerOp, joinPredicates, merger, subQueryInner)
|
||||
case *ApplyJoin:
|
||||
// Trying to merge the subquery with the left-hand or right-hand side of the join
|
||||
|
||||
if outerOp.LeftJoin {
|
||||
return nil, nil
|
||||
}
|
||||
newMergefunc := func(a, b *Route) (*Route, error) {
|
||||
rt, err := merger(a, b)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
outerOp.RHS, err = rewriteColumnsInSubqueryOpForApplyJoin(ctx, outerOp.RHS, outerOp, subQueryInner)
|
||||
return rt, err
|
||||
}
|
||||
merged, err = tryMergeSubQueryOp(ctx, outerOp.LHS, subq, subQueryInner, joinPredicates, newMergefunc)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if merged != nil {
|
||||
outerOp.LHS = merged
|
||||
return outerOp, nil
|
||||
}
|
||||
|
||||
newMergefunc = func(a, b *Route) (*Route, error) {
|
||||
rt, err := merger(a, b)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
outerOp.LHS, err = rewriteColumnsInSubqueryOpForApplyJoin(ctx, outerOp.LHS, outerOp, subQueryInner)
|
||||
return rt, err
|
||||
}
|
||||
merged, err = tryMergeSubQueryOp(ctx, outerOp.RHS, subq, subQueryInner, joinPredicates, newMergefunc)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if merged != nil {
|
||||
outerOp.RHS = merged
|
||||
return outerOp, nil
|
||||
}
|
||||
return nil, nil
|
||||
return tryMergeSubqueryWithJoin(ctx, subq, outerOp, joinPredicates, merger, subQueryInner)
|
||||
default:
|
||||
return nil, nil
|
||||
}
|
||||
}
|
||||
|
||||
// shouldTryMergingSubquery returns whether there is a possibility of merging the subquery with the outer route
|
||||
// For some cases like Reference, we shouldn't try to merge them, since the common logic of tryMerge will allow them to
|
||||
// be merged, even though they shouldn't
|
||||
func shouldTryMergingSubquery(outerOp *Route, subq abstract.PhysicalOperator) bool {
|
||||
if outerOp.RouteOpCode == engine.Reference {
|
||||
subqRoute, isRoute := subq.(*Route)
|
||||
if !isRoute {
|
||||
return false
|
||||
}
|
||||
return subqRoute.RouteOpCode.IsSingleShard()
|
||||
func tryMergeSubqueryWithRoute(
|
||||
ctx *plancontext.PlanningContext,
|
||||
subq abstract.PhysicalOperator,
|
||||
outerOp *Route,
|
||||
joinPredicates []sqlparser.Expr,
|
||||
merger mergeFunc,
|
||||
subQueryInner *SubQueryInner,
|
||||
) (abstract.PhysicalOperator, error) {
|
||||
subqueryRoute, isRoute := subq.(*Route)
|
||||
if !isRoute {
|
||||
return nil, nil
|
||||
}
|
||||
return true
|
||||
|
||||
if outerOp.RouteOpCode == engine.Reference && !subqueryRoute.IsSingleShard() {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
merged, err := tryMerge(ctx, outerOp, subq, joinPredicates, merger)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// If the subqueries could be merged here, we're done
|
||||
if merged != nil {
|
||||
return merged, err
|
||||
}
|
||||
|
||||
if !isMergeable(ctx, subQueryInner.ExtractedSubquery.Subquery.Select, subq) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// Special case: Inner query won't return any results / is not routable.
|
||||
if subqueryRoute.RouteOpCode == engine.None {
|
||||
merged, err := merger(outerOp, subqueryRoute)
|
||||
return merged, err
|
||||
}
|
||||
|
||||
// Inner subqueries can be merged with the outer subquery as long as
|
||||
// the inner query is a single column selection, and that single column has a matching
|
||||
// vindex on the outer query's operand.
|
||||
if canMergeSubqueryOnColumnSelection(ctx, outerOp, subqueryRoute, subQueryInner.ExtractedSubquery) {
|
||||
merged, err := merger(outerOp, subqueryRoute)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if merged != nil {
|
||||
// since we inlined the subquery into the outer query, new vindex options might have been enabled,
|
||||
// so we go over our current options to check if anything better has come up.
|
||||
merged.PickBestAvailableVindex()
|
||||
return merged, err
|
||||
}
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// rewriteColumnsInSubqueryOpForApplyJoin rewrites the columns that appear from the other side
|
||||
func tryMergeSubqueryWithJoin(
|
||||
ctx *plancontext.PlanningContext,
|
||||
subq abstract.PhysicalOperator,
|
||||
outerOp *ApplyJoin,
|
||||
joinPredicates []sqlparser.Expr,
|
||||
merger mergeFunc,
|
||||
subQueryInner *SubQueryInner,
|
||||
) (abstract.PhysicalOperator, error) {
|
||||
// Trying to merge the subquery with the left-hand or right-hand side of the join
|
||||
|
||||
if outerOp.LeftJoin {
|
||||
return nil, nil
|
||||
}
|
||||
newMergefunc := func(a, b *Route) (*Route, error) {
|
||||
rt, err := merger(a, b)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
outerOp.RHS, err = rewriteColumnsInSubqueryOpForJoin(ctx, outerOp.RHS, outerOp, subQueryInner)
|
||||
return rt, err
|
||||
}
|
||||
merged, err := tryMergeSubQueryOp(ctx, outerOp.LHS, subq, subQueryInner, joinPredicates, newMergefunc)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if merged != nil {
|
||||
outerOp.LHS = merged
|
||||
return outerOp, nil
|
||||
}
|
||||
|
||||
newMergefunc = func(a, b *Route) (*Route, error) {
|
||||
rt, err := merger(a, b)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
outerOp.LHS, err = rewriteColumnsInSubqueryOpForJoin(ctx, outerOp.LHS, outerOp, subQueryInner)
|
||||
return rt, err
|
||||
}
|
||||
merged, err = tryMergeSubQueryOp(ctx, outerOp.RHS, subq, subQueryInner, joinPredicates, newMergefunc)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if merged != nil {
|
||||
outerOp.RHS = merged
|
||||
return outerOp, nil
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// rewriteColumnsInSubqueryOpForJoin rewrites the columns that appear from the other side
|
||||
// of the join. For example, let's say we merged a subquery on the right side of a join tree
|
||||
// If it was using any columns from the left side then they need to be replaced by bind variables supplied
|
||||
// from that side.
|
||||
// outerTree is the joinTree within whose children the subquery lives in
|
||||
// the child of joinTree which does not contain the subquery is the otherTree
|
||||
func rewriteColumnsInSubqueryOpForApplyJoin(
|
||||
func rewriteColumnsInSubqueryOpForJoin(
|
||||
ctx *plancontext.PlanningContext,
|
||||
innerOp abstract.PhysicalOperator,
|
||||
outerTree *ApplyJoin,
|
||||
|
@ -333,3 +432,46 @@ func createCorrelatedSubqueryOp(
|
|||
LHSColumns: lhsCols,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// canMergeSubqueryOnColumnSelection will return true if the predicate used allows us to merge the two subqueries
|
||||
// into a single Route. This can be done if we are comparing two columns that contain data that is guaranteed
|
||||
// to exist on the same shard.
|
||||
func canMergeSubqueryOnColumnSelection(ctx *plancontext.PlanningContext, a, b *Route, predicate *sqlparser.ExtractedSubquery) bool {
|
||||
left := predicate.OtherSide
|
||||
opCode := predicate.OpCode
|
||||
if opCode != int(engine.PulloutValue) && opCode != int(engine.PulloutIn) {
|
||||
return false
|
||||
}
|
||||
|
||||
lVindex := findColumnVindex(ctx, a, left)
|
||||
if lVindex == nil || !lVindex.IsUnique() {
|
||||
return false
|
||||
}
|
||||
|
||||
rightSelection := extractSingleColumnSubquerySelection(predicate.Subquery)
|
||||
if rightSelection == nil {
|
||||
return false
|
||||
}
|
||||
|
||||
rVindex := findColumnVindex(ctx, b, rightSelection)
|
||||
if rVindex == nil {
|
||||
return false
|
||||
}
|
||||
return rVindex == lVindex
|
||||
}
|
||||
|
||||
// Searches for the single column returned from a subquery, like the `col` in `(SELECT col FROM tbl)`
|
||||
func extractSingleColumnSubquerySelection(subquery *sqlparser.Subquery) *sqlparser.ColName {
|
||||
if subquery.Select.GetColumnCount() != 1 {
|
||||
return nil
|
||||
}
|
||||
|
||||
columnExpr := subquery.Select.GetColumns()[0]
|
||||
|
||||
aliasedExpr, ok := columnExpr.(*sqlparser.AliasedExpr)
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
|
||||
return getColName(aliasedExpr.Expr)
|
||||
}
|
||||
|
|
|
@ -5707,44 +5707,19 @@ Gen4 plan same as above
|
|||
"QueryType": "SELECT",
|
||||
"Original": "SELECT music.id FROM music WHERE music.id IN (SELECT music.id FROM music WHERE music.user_id IN (1, 2, 3))",
|
||||
"Instructions": {
|
||||
"OperatorType": "Subquery",
|
||||
"Variant": "PulloutIn",
|
||||
"PulloutVars": [
|
||||
"__sq_has_values1",
|
||||
"__sq1"
|
||||
"OperatorType": "Route",
|
||||
"Variant": "IN",
|
||||
"Keyspace": {
|
||||
"Name": "user",
|
||||
"Sharded": true
|
||||
},
|
||||
"FieldQuery": "select music.id from music where 1 != 1",
|
||||
"Query": "select music.id from music where music.id in (select music.id from music where music.user_id in ::__vals)",
|
||||
"Table": "music",
|
||||
"Values": [
|
||||
"(INT64(1), INT64(2), INT64(3))"
|
||||
],
|
||||
"Inputs": [
|
||||
{
|
||||
"OperatorType": "Route",
|
||||
"Variant": "IN",
|
||||
"Keyspace": {
|
||||
"Name": "user",
|
||||
"Sharded": true
|
||||
},
|
||||
"FieldQuery": "select music.id from music where 1 != 1",
|
||||
"Query": "select music.id from music where music.user_id in ::__vals",
|
||||
"Table": "music",
|
||||
"Values": [
|
||||
"(INT64(1), INT64(2), INT64(3))"
|
||||
],
|
||||
"Vindex": "user_index"
|
||||
},
|
||||
{
|
||||
"OperatorType": "Route",
|
||||
"Variant": "IN",
|
||||
"Keyspace": {
|
||||
"Name": "user",
|
||||
"Sharded": true
|
||||
},
|
||||
"FieldQuery": "select music.id from music where 1 != 1",
|
||||
"Query": "select music.id from music where :__sq_has_values1 = 1 and music.id in ::__vals",
|
||||
"Table": "music",
|
||||
"Values": [
|
||||
":__sq1"
|
||||
],
|
||||
"Vindex": "music_user_map"
|
||||
}
|
||||
]
|
||||
"Vindex": "user_index"
|
||||
},
|
||||
"TablesUsed": [
|
||||
"user.music"
|
||||
|
@ -5801,44 +5776,19 @@ Gen4 plan same as above
|
|||
"QueryType": "SELECT",
|
||||
"Original": "SELECT music.id FROM music WHERE music.id IN (SELECT * FROM (SELECT music.id FROM music WHERE music.user_id IN (1, 2, 3)) _inner)",
|
||||
"Instructions": {
|
||||
"OperatorType": "Subquery",
|
||||
"Variant": "PulloutIn",
|
||||
"PulloutVars": [
|
||||
"__sq_has_values1",
|
||||
"__sq1"
|
||||
"OperatorType": "Route",
|
||||
"Variant": "IN",
|
||||
"Keyspace": {
|
||||
"Name": "user",
|
||||
"Sharded": true
|
||||
},
|
||||
"FieldQuery": "select music.id from music where 1 != 1",
|
||||
"Query": "select music.id from music where music.id in (select _inner.id from (select music.id from music where music.user_id in ::__vals) as _inner)",
|
||||
"Table": "music",
|
||||
"Values": [
|
||||
"(INT64(1), INT64(2), INT64(3))"
|
||||
],
|
||||
"Inputs": [
|
||||
{
|
||||
"OperatorType": "Route",
|
||||
"Variant": "IN",
|
||||
"Keyspace": {
|
||||
"Name": "user",
|
||||
"Sharded": true
|
||||
},
|
||||
"FieldQuery": "select _inner.id from (select music.id from music where 1 != 1) as _inner where 1 != 1",
|
||||
"Query": "select _inner.id from (select music.id from music where music.user_id in ::__vals) as _inner",
|
||||
"Table": "music",
|
||||
"Values": [
|
||||
"(INT64(1), INT64(2), INT64(3))"
|
||||
],
|
||||
"Vindex": "user_index"
|
||||
},
|
||||
{
|
||||
"OperatorType": "Route",
|
||||
"Variant": "IN",
|
||||
"Keyspace": {
|
||||
"Name": "user",
|
||||
"Sharded": true
|
||||
},
|
||||
"FieldQuery": "select music.id from music where 1 != 1",
|
||||
"Query": "select music.id from music where :__sq_has_values1 = 1 and music.id in ::__vals",
|
||||
"Table": "music",
|
||||
"Values": [
|
||||
":__sq1"
|
||||
],
|
||||
"Vindex": "music_user_map"
|
||||
}
|
||||
]
|
||||
"Vindex": "user_index"
|
||||
},
|
||||
"TablesUsed": [
|
||||
"user.music"
|
||||
|
@ -5891,40 +5841,19 @@ Gen4 plan same as above
|
|||
"QueryType": "SELECT",
|
||||
"Original": "SELECT music.id FROM music WHERE music.id IN (SELECT music.id FROM music WHERE music.foo = 'bar') AND music.user_id IN (3, 4, 5)",
|
||||
"Instructions": {
|
||||
"OperatorType": "Subquery",
|
||||
"Variant": "PulloutIn",
|
||||
"PulloutVars": [
|
||||
"__sq_has_values1",
|
||||
"__sq1"
|
||||
"OperatorType": "Route",
|
||||
"Variant": "IN",
|
||||
"Keyspace": {
|
||||
"Name": "user",
|
||||
"Sharded": true
|
||||
},
|
||||
"FieldQuery": "select music.id from music where 1 != 1",
|
||||
"Query": "select music.id from music where music.id in (select music.id from music where music.foo = 'bar') and music.user_id in ::__vals",
|
||||
"Table": "music",
|
||||
"Values": [
|
||||
"(INT64(3), INT64(4), INT64(5))"
|
||||
],
|
||||
"Inputs": [
|
||||
{
|
||||
"OperatorType": "Route",
|
||||
"Variant": "Scatter",
|
||||
"Keyspace": {
|
||||
"Name": "user",
|
||||
"Sharded": true
|
||||
},
|
||||
"FieldQuery": "select music.id from music where 1 != 1",
|
||||
"Query": "select music.id from music where music.foo = 'bar'",
|
||||
"Table": "music"
|
||||
},
|
||||
{
|
||||
"OperatorType": "Route",
|
||||
"Variant": "IN",
|
||||
"Keyspace": {
|
||||
"Name": "user",
|
||||
"Sharded": true
|
||||
},
|
||||
"FieldQuery": "select music.id from music where 1 != 1",
|
||||
"Query": "select music.id from music where :__sq_has_values1 = 1 and music.id in ::__sq1 and music.user_id in ::__vals",
|
||||
"Table": "music",
|
||||
"Values": [
|
||||
"(INT64(3), INT64(4), INT64(5))"
|
||||
],
|
||||
"Vindex": "user_index"
|
||||
}
|
||||
]
|
||||
"Vindex": "user_index"
|
||||
},
|
||||
"TablesUsed": [
|
||||
"user.music"
|
||||
|
@ -5981,44 +5910,19 @@ Gen4 plan same as above
|
|||
"QueryType": "SELECT",
|
||||
"Original": "SELECT music.id FROM music WHERE music.id IN (SELECT music.id FROM music WHERE music.user_id IN (1, 2, 3)) and music.user_id = 5",
|
||||
"Instructions": {
|
||||
"OperatorType": "Subquery",
|
||||
"Variant": "PulloutIn",
|
||||
"PulloutVars": [
|
||||
"__sq_has_values1",
|
||||
"__sq1"
|
||||
"OperatorType": "Route",
|
||||
"Variant": "EqualUnique",
|
||||
"Keyspace": {
|
||||
"Name": "user",
|
||||
"Sharded": true
|
||||
},
|
||||
"FieldQuery": "select music.id from music where 1 != 1",
|
||||
"Query": "select music.id from music where music.id in (select music.id from music where music.user_id in (1, 2, 3)) and music.user_id = 5",
|
||||
"Table": "music",
|
||||
"Values": [
|
||||
"INT64(5)"
|
||||
],
|
||||
"Inputs": [
|
||||
{
|
||||
"OperatorType": "Route",
|
||||
"Variant": "IN",
|
||||
"Keyspace": {
|
||||
"Name": "user",
|
||||
"Sharded": true
|
||||
},
|
||||
"FieldQuery": "select music.id from music where 1 != 1",
|
||||
"Query": "select music.id from music where music.user_id in ::__vals",
|
||||
"Table": "music",
|
||||
"Values": [
|
||||
"(INT64(1), INT64(2), INT64(3))"
|
||||
],
|
||||
"Vindex": "user_index"
|
||||
},
|
||||
{
|
||||
"OperatorType": "Route",
|
||||
"Variant": "EqualUnique",
|
||||
"Keyspace": {
|
||||
"Name": "user",
|
||||
"Sharded": true
|
||||
},
|
||||
"FieldQuery": "select music.id from music where 1 != 1",
|
||||
"Query": "select music.id from music where :__sq_has_values1 = 1 and music.id in ::__sq1 and music.user_id = 5",
|
||||
"Table": "music",
|
||||
"Values": [
|
||||
"INT64(5)"
|
||||
],
|
||||
"Vindex": "user_index"
|
||||
}
|
||||
]
|
||||
"Vindex": "user_index"
|
||||
},
|
||||
"TablesUsed": [
|
||||
"user.music"
|
||||
|
@ -6071,40 +5975,15 @@ Gen4 plan same as above
|
|||
"QueryType": "SELECT",
|
||||
"Original": "SELECT music.id FROM music WHERE music.id IN (SELECT music.id FROM music WHERE music.user_id IN (1, 2, 3)) OR music.user_id = 5",
|
||||
"Instructions": {
|
||||
"OperatorType": "Subquery",
|
||||
"Variant": "PulloutIn",
|
||||
"PulloutVars": [
|
||||
"__sq_has_values1",
|
||||
"__sq1"
|
||||
],
|
||||
"Inputs": [
|
||||
{
|
||||
"OperatorType": "Route",
|
||||
"Variant": "IN",
|
||||
"Keyspace": {
|
||||
"Name": "user",
|
||||
"Sharded": true
|
||||
},
|
||||
"FieldQuery": "select music.id from music where 1 != 1",
|
||||
"Query": "select music.id from music where music.user_id in ::__vals",
|
||||
"Table": "music",
|
||||
"Values": [
|
||||
"(INT64(1), INT64(2), INT64(3))"
|
||||
],
|
||||
"Vindex": "user_index"
|
||||
},
|
||||
{
|
||||
"OperatorType": "Route",
|
||||
"Variant": "Scatter",
|
||||
"Keyspace": {
|
||||
"Name": "user",
|
||||
"Sharded": true
|
||||
},
|
||||
"FieldQuery": "select music.id from music where 1 != 1",
|
||||
"Query": "select music.id from music where :__sq_has_values1 = 1 and music.id in ::__sq1 or music.user_id = 5",
|
||||
"Table": "music"
|
||||
}
|
||||
]
|
||||
"OperatorType": "Route",
|
||||
"Variant": "Scatter",
|
||||
"Keyspace": {
|
||||
"Name": "user",
|
||||
"Sharded": true
|
||||
},
|
||||
"FieldQuery": "select music.id from music where 1 != 1",
|
||||
"Query": "select music.id from music where music.id in (select music.id from music where music.user_id in (1, 2, 3)) or music.user_id = 5",
|
||||
"Table": "music"
|
||||
},
|
||||
"TablesUsed": [
|
||||
"user.music"
|
||||
|
@ -6157,40 +6036,15 @@ Gen4 plan same as above
|
|||
"QueryType": "SELECT",
|
||||
"Original": "SELECT `music`.id FROM `music` WHERE music.id IN (SELECT music.id FROM music WHERE music.user_id IN (NULL)) AND music.user_id = 5",
|
||||
"Instructions": {
|
||||
"OperatorType": "Subquery",
|
||||
"Variant": "PulloutIn",
|
||||
"PulloutVars": [
|
||||
"__sq_has_values1",
|
||||
"__sq1"
|
||||
],
|
||||
"Inputs": [
|
||||
{
|
||||
"OperatorType": "Route",
|
||||
"Variant": "None",
|
||||
"Keyspace": {
|
||||
"Name": "user",
|
||||
"Sharded": true
|
||||
},
|
||||
"FieldQuery": "select music.id from music where 1 != 1",
|
||||
"Query": "select music.id from music where music.user_id in (null)",
|
||||
"Table": "music"
|
||||
},
|
||||
{
|
||||
"OperatorType": "Route",
|
||||
"Variant": "EqualUnique",
|
||||
"Keyspace": {
|
||||
"Name": "user",
|
||||
"Sharded": true
|
||||
},
|
||||
"FieldQuery": "select music.id from music where 1 != 1",
|
||||
"Query": "select music.id from music where :__sq_has_values1 = 1 and music.id in ::__sq1 and music.user_id = 5",
|
||||
"Table": "music",
|
||||
"Values": [
|
||||
"INT64(5)"
|
||||
],
|
||||
"Vindex": "user_index"
|
||||
}
|
||||
]
|
||||
"OperatorType": "Route",
|
||||
"Variant": "None",
|
||||
"Keyspace": {
|
||||
"Name": "user",
|
||||
"Sharded": true
|
||||
},
|
||||
"FieldQuery": "select music.id from music where 1 != 1",
|
||||
"Query": "select music.id from music where music.id in (select music.id from music where music.user_id in (null)) and music.user_id = 5",
|
||||
"Table": "music"
|
||||
},
|
||||
"TablesUsed": [
|
||||
"user.music"
|
||||
|
@ -6239,36 +6093,15 @@ Gen4 plan same as above
|
|||
"QueryType": "SELECT",
|
||||
"Original": "SELECT `music`.id FROM `music` WHERE music.id IN (SELECT music.id FROM music WHERE music.user_id IN (NULL)) OR music.user_id = 5",
|
||||
"Instructions": {
|
||||
"OperatorType": "Subquery",
|
||||
"Variant": "PulloutIn",
|
||||
"PulloutVars": [
|
||||
"__sq_has_values1",
|
||||
"__sq1"
|
||||
],
|
||||
"Inputs": [
|
||||
{
|
||||
"OperatorType": "Route",
|
||||
"Variant": "None",
|
||||
"Keyspace": {
|
||||
"Name": "user",
|
||||
"Sharded": true
|
||||
},
|
||||
"FieldQuery": "select music.id from music where 1 != 1",
|
||||
"Query": "select music.id from music where music.user_id in (null)",
|
||||
"Table": "music"
|
||||
},
|
||||
{
|
||||
"OperatorType": "Route",
|
||||
"Variant": "Scatter",
|
||||
"Keyspace": {
|
||||
"Name": "user",
|
||||
"Sharded": true
|
||||
},
|
||||
"FieldQuery": "select music.id from music where 1 != 1",
|
||||
"Query": "select music.id from music where :__sq_has_values1 = 1 and music.id in ::__sq1 or music.user_id = 5",
|
||||
"Table": "music"
|
||||
}
|
||||
]
|
||||
"OperatorType": "Route",
|
||||
"Variant": "Scatter",
|
||||
"Keyspace": {
|
||||
"Name": "user",
|
||||
"Sharded": true
|
||||
},
|
||||
"FieldQuery": "select music.id from music where 1 != 1",
|
||||
"Query": "select music.id from music where music.id in (select music.id from music where music.user_id in (null)) or music.user_id = 5",
|
||||
"Table": "music"
|
||||
},
|
||||
"TablesUsed": [
|
||||
"user.music"
|
||||
|
@ -6321,40 +6154,15 @@ Gen4 plan same as above
|
|||
"QueryType": "SELECT",
|
||||
"Original": "SELECT music.id FROM music WHERE music.id IN (SELECT music.id FROM music WHERE music.genre = 'pop')",
|
||||
"Instructions": {
|
||||
"OperatorType": "Subquery",
|
||||
"Variant": "PulloutIn",
|
||||
"PulloutVars": [
|
||||
"__sq_has_values1",
|
||||
"__sq1"
|
||||
],
|
||||
"Inputs": [
|
||||
{
|
||||
"OperatorType": "Route",
|
||||
"Variant": "Scatter",
|
||||
"Keyspace": {
|
||||
"Name": "user",
|
||||
"Sharded": true
|
||||
},
|
||||
"FieldQuery": "select music.id from music where 1 != 1",
|
||||
"Query": "select music.id from music where music.genre = 'pop'",
|
||||
"Table": "music"
|
||||
},
|
||||
{
|
||||
"OperatorType": "Route",
|
||||
"Variant": "IN",
|
||||
"Keyspace": {
|
||||
"Name": "user",
|
||||
"Sharded": true
|
||||
},
|
||||
"FieldQuery": "select music.id from music where 1 != 1",
|
||||
"Query": "select music.id from music where :__sq_has_values1 = 1 and music.id in ::__vals",
|
||||
"Table": "music",
|
||||
"Values": [
|
||||
":__sq1"
|
||||
],
|
||||
"Vindex": "music_user_map"
|
||||
}
|
||||
]
|
||||
"OperatorType": "Route",
|
||||
"Variant": "Scatter",
|
||||
"Keyspace": {
|
||||
"Name": "user",
|
||||
"Sharded": true
|
||||
},
|
||||
"FieldQuery": "select music.id from music where 1 != 1",
|
||||
"Query": "select music.id from music where music.id in (select music.id from music where music.genre = 'pop')",
|
||||
"Table": "music"
|
||||
},
|
||||
"TablesUsed": [
|
||||
"user.music"
|
||||
|
@ -6407,40 +6215,15 @@ Gen4 plan same as above
|
|||
"QueryType": "SELECT",
|
||||
"Original": "SELECT music.id FROM music WHERE music.id IN (SELECT music.id FROM music WHERE music.genre = 'pop' GROUP BY music.id)",
|
||||
"Instructions": {
|
||||
"OperatorType": "Subquery",
|
||||
"Variant": "PulloutIn",
|
||||
"PulloutVars": [
|
||||
"__sq_has_values1",
|
||||
"__sq1"
|
||||
],
|
||||
"Inputs": [
|
||||
{
|
||||
"OperatorType": "Route",
|
||||
"Variant": "Scatter",
|
||||
"Keyspace": {
|
||||
"Name": "user",
|
||||
"Sharded": true
|
||||
},
|
||||
"FieldQuery": "select music.id from music where 1 != 1 group by music.id",
|
||||
"Query": "select music.id from music where music.genre = 'pop' group by music.id",
|
||||
"Table": "music"
|
||||
},
|
||||
{
|
||||
"OperatorType": "Route",
|
||||
"Variant": "IN",
|
||||
"Keyspace": {
|
||||
"Name": "user",
|
||||
"Sharded": true
|
||||
},
|
||||
"FieldQuery": "select music.id from music where 1 != 1",
|
||||
"Query": "select music.id from music where :__sq_has_values1 = 1 and music.id in ::__vals",
|
||||
"Table": "music",
|
||||
"Values": [
|
||||
":__sq1"
|
||||
],
|
||||
"Vindex": "music_user_map"
|
||||
}
|
||||
]
|
||||
"OperatorType": "Route",
|
||||
"Variant": "Scatter",
|
||||
"Keyspace": {
|
||||
"Name": "user",
|
||||
"Sharded": true
|
||||
},
|
||||
"FieldQuery": "select music.id from music where 1 != 1",
|
||||
"Query": "select music.id from music where music.id in (select music.id from music where music.genre = 'pop' group by music.id)",
|
||||
"Table": "music"
|
||||
},
|
||||
"TablesUsed": [
|
||||
"user.music"
|
||||
|
@ -6652,44 +6435,19 @@ Gen4 plan same as above
|
|||
"QueryType": "SELECT",
|
||||
"Original": "SELECT music.id FROM music WHERE music.id IN (SELECT MAX(music.id) FROM music WHERE music.user_id IN (5, 6) GROUP BY music.user_id)",
|
||||
"Instructions": {
|
||||
"OperatorType": "Subquery",
|
||||
"Variant": "PulloutIn",
|
||||
"PulloutVars": [
|
||||
"__sq_has_values1",
|
||||
"__sq1"
|
||||
"OperatorType": "Route",
|
||||
"Variant": "IN",
|
||||
"Keyspace": {
|
||||
"Name": "user",
|
||||
"Sharded": true
|
||||
},
|
||||
"FieldQuery": "select music.id from music where 1 != 1",
|
||||
"Query": "select music.id from music where music.id in (select max(music.id) from music where music.user_id in ::__vals group by music.user_id)",
|
||||
"Table": "music",
|
||||
"Values": [
|
||||
"(INT64(5), INT64(6))"
|
||||
],
|
||||
"Inputs": [
|
||||
{
|
||||
"OperatorType": "Route",
|
||||
"Variant": "IN",
|
||||
"Keyspace": {
|
||||
"Name": "user",
|
||||
"Sharded": true
|
||||
},
|
||||
"FieldQuery": "select max(music.id) from music where 1 != 1 group by music.user_id",
|
||||
"Query": "select max(music.id) from music where music.user_id in ::__vals group by music.user_id",
|
||||
"Table": "music",
|
||||
"Values": [
|
||||
"(INT64(5), INT64(6))"
|
||||
],
|
||||
"Vindex": "user_index"
|
||||
},
|
||||
{
|
||||
"OperatorType": "Route",
|
||||
"Variant": "IN",
|
||||
"Keyspace": {
|
||||
"Name": "user",
|
||||
"Sharded": true
|
||||
},
|
||||
"FieldQuery": "select music.id from music where 1 != 1",
|
||||
"Query": "select music.id from music where :__sq_has_values1 = 1 and music.id in ::__vals",
|
||||
"Table": "music",
|
||||
"Values": [
|
||||
":__sq1"
|
||||
],
|
||||
"Vindex": "music_user_map"
|
||||
}
|
||||
]
|
||||
"Vindex": "user_index"
|
||||
},
|
||||
"TablesUsed": [
|
||||
"user.music"
|
||||
|
@ -7042,44 +6800,19 @@ Gen4 plan same as above
|
|||
"QueryType": "SELECT",
|
||||
"Original": "SELECT music.id FROM music WHERE music.id IN (SELECT * FROM (SELECT * FROM (SELECT music.id FROM music WHERE music.user_id = 5 LIMIT 10) subquery_for_limit) subquery_for_limit)",
|
||||
"Instructions": {
|
||||
"OperatorType": "Subquery",
|
||||
"Variant": "PulloutIn",
|
||||
"PulloutVars": [
|
||||
"__sq_has_values1",
|
||||
"__sq1"
|
||||
"OperatorType": "Route",
|
||||
"Variant": "EqualUnique",
|
||||
"Keyspace": {
|
||||
"Name": "user",
|
||||
"Sharded": true
|
||||
},
|
||||
"FieldQuery": "select music.id from music where 1 != 1",
|
||||
"Query": "select music.id from music where music.id in (select subquery_for_limit.id from (select subquery_for_limit.id from (select music.id from music where music.user_id = 5 limit 10) as subquery_for_limit) as subquery_for_limit)",
|
||||
"Table": "music",
|
||||
"Values": [
|
||||
"INT64(5)"
|
||||
],
|
||||
"Inputs": [
|
||||
{
|
||||
"OperatorType": "Route",
|
||||
"Variant": "EqualUnique",
|
||||
"Keyspace": {
|
||||
"Name": "user",
|
||||
"Sharded": true
|
||||
},
|
||||
"FieldQuery": "select subquery_for_limit.id from (select subquery_for_limit.id from (select music.id from music where 1 != 1) as subquery_for_limit where 1 != 1) as subquery_for_limit where 1 != 1",
|
||||
"Query": "select subquery_for_limit.id from (select subquery_for_limit.id from (select music.id from music where music.user_id = 5 limit 10) as subquery_for_limit) as subquery_for_limit",
|
||||
"Table": "music",
|
||||
"Values": [
|
||||
"INT64(5)"
|
||||
],
|
||||
"Vindex": "user_index"
|
||||
},
|
||||
{
|
||||
"OperatorType": "Route",
|
||||
"Variant": "IN",
|
||||
"Keyspace": {
|
||||
"Name": "user",
|
||||
"Sharded": true
|
||||
},
|
||||
"FieldQuery": "select music.id from music where 1 != 1",
|
||||
"Query": "select music.id from music where :__sq_has_values1 = 1 and music.id in ::__vals",
|
||||
"Table": "music",
|
||||
"Values": [
|
||||
":__sq1"
|
||||
],
|
||||
"Vindex": "music_user_map"
|
||||
}
|
||||
]
|
||||
"Vindex": "user_index"
|
||||
},
|
||||
"TablesUsed": [
|
||||
"user.music"
|
||||
|
@ -7158,44 +6891,19 @@ Gen4 plan same as above
|
|||
"QueryType": "SELECT",
|
||||
"Original": "SELECT music.id FROM music WHERE music.id IN (SELECT * FROM (SELECT * FROM (SELECT music.id FROM music WHERE music.user_id IN (5) LIMIT 10) subquery_for_limit) subquery_for_limit)",
|
||||
"Instructions": {
|
||||
"OperatorType": "Subquery",
|
||||
"Variant": "PulloutIn",
|
||||
"PulloutVars": [
|
||||
"__sq_has_values1",
|
||||
"__sq1"
|
||||
"OperatorType": "Route",
|
||||
"Variant": "EqualUnique",
|
||||
"Keyspace": {
|
||||
"Name": "user",
|
||||
"Sharded": true
|
||||
},
|
||||
"FieldQuery": "select music.id from music where 1 != 1",
|
||||
"Query": "select music.id from music where music.id in (select subquery_for_limit.id from (select subquery_for_limit.id from (select music.id from music where music.user_id in (5) limit 10) as subquery_for_limit) as subquery_for_limit)",
|
||||
"Table": "music",
|
||||
"Values": [
|
||||
"INT64(5)"
|
||||
],
|
||||
"Inputs": [
|
||||
{
|
||||
"OperatorType": "Route",
|
||||
"Variant": "EqualUnique",
|
||||
"Keyspace": {
|
||||
"Name": "user",
|
||||
"Sharded": true
|
||||
},
|
||||
"FieldQuery": "select subquery_for_limit.id from (select subquery_for_limit.id from (select music.id from music where 1 != 1) as subquery_for_limit where 1 != 1) as subquery_for_limit where 1 != 1",
|
||||
"Query": "select subquery_for_limit.id from (select subquery_for_limit.id from (select music.id from music where music.user_id in (5) limit 10) as subquery_for_limit) as subquery_for_limit",
|
||||
"Table": "music",
|
||||
"Values": [
|
||||
"INT64(5)"
|
||||
],
|
||||
"Vindex": "user_index"
|
||||
},
|
||||
{
|
||||
"OperatorType": "Route",
|
||||
"Variant": "IN",
|
||||
"Keyspace": {
|
||||
"Name": "user",
|
||||
"Sharded": true
|
||||
},
|
||||
"FieldQuery": "select music.id from music where 1 != 1",
|
||||
"Query": "select music.id from music where :__sq_has_values1 = 1 and music.id in ::__vals",
|
||||
"Table": "music",
|
||||
"Values": [
|
||||
":__sq1"
|
||||
],
|
||||
"Vindex": "music_user_map"
|
||||
}
|
||||
]
|
||||
"Vindex": "user_index"
|
||||
},
|
||||
"TablesUsed": [
|
||||
"user.music"
|
||||
|
@ -7500,40 +7208,15 @@ Gen4 plan same as above
|
|||
"QueryType": "SELECT",
|
||||
"Original": "SELECT music.id FROM music WHERE music.id IN (SELECT music.id FROM music WHERE music.user_id IN (NULL))",
|
||||
"Instructions": {
|
||||
"OperatorType": "Subquery",
|
||||
"Variant": "PulloutIn",
|
||||
"PulloutVars": [
|
||||
"__sq_has_values1",
|
||||
"__sq1"
|
||||
],
|
||||
"Inputs": [
|
||||
{
|
||||
"OperatorType": "Route",
|
||||
"Variant": "None",
|
||||
"Keyspace": {
|
||||
"Name": "user",
|
||||
"Sharded": true
|
||||
},
|
||||
"FieldQuery": "select music.id from music where 1 != 1",
|
||||
"Query": "select music.id from music where music.user_id in (null)",
|
||||
"Table": "music"
|
||||
},
|
||||
{
|
||||
"OperatorType": "Route",
|
||||
"Variant": "IN",
|
||||
"Keyspace": {
|
||||
"Name": "user",
|
||||
"Sharded": true
|
||||
},
|
||||
"FieldQuery": "select music.id from music where 1 != 1",
|
||||
"Query": "select music.id from music where :__sq_has_values1 = 1 and music.id in ::__vals",
|
||||
"Table": "music",
|
||||
"Values": [
|
||||
":__sq1"
|
||||
],
|
||||
"Vindex": "music_user_map"
|
||||
}
|
||||
]
|
||||
"OperatorType": "Route",
|
||||
"Variant": "None",
|
||||
"Keyspace": {
|
||||
"Name": "user",
|
||||
"Sharded": true
|
||||
},
|
||||
"FieldQuery": "select music.id from music where 1 != 1",
|
||||
"Query": "select music.id from music where music.id in (select music.id from music where music.user_id in (null))",
|
||||
"Table": "music"
|
||||
},
|
||||
"TablesUsed": [
|
||||
"user.music"
|
||||
|
@ -7586,40 +7269,15 @@ Gen4 plan same as above
|
|||
"QueryType": "SELECT",
|
||||
"Original": "SELECT music.id FROM music WHERE music.id IN (SELECT music.id FROM music WHERE music.user_id IN (NULL)) AND music.user_id = 5",
|
||||
"Instructions": {
|
||||
"OperatorType": "Subquery",
|
||||
"Variant": "PulloutIn",
|
||||
"PulloutVars": [
|
||||
"__sq_has_values1",
|
||||
"__sq1"
|
||||
],
|
||||
"Inputs": [
|
||||
{
|
||||
"OperatorType": "Route",
|
||||
"Variant": "None",
|
||||
"Keyspace": {
|
||||
"Name": "user",
|
||||
"Sharded": true
|
||||
},
|
||||
"FieldQuery": "select music.id from music where 1 != 1",
|
||||
"Query": "select music.id from music where music.user_id in (null)",
|
||||
"Table": "music"
|
||||
},
|
||||
{
|
||||
"OperatorType": "Route",
|
||||
"Variant": "EqualUnique",
|
||||
"Keyspace": {
|
||||
"Name": "user",
|
||||
"Sharded": true
|
||||
},
|
||||
"FieldQuery": "select music.id from music where 1 != 1",
|
||||
"Query": "select music.id from music where :__sq_has_values1 = 1 and music.id in ::__sq1 and music.user_id = 5",
|
||||
"Table": "music",
|
||||
"Values": [
|
||||
"INT64(5)"
|
||||
],
|
||||
"Vindex": "user_index"
|
||||
}
|
||||
]
|
||||
"OperatorType": "Route",
|
||||
"Variant": "None",
|
||||
"Keyspace": {
|
||||
"Name": "user",
|
||||
"Sharded": true
|
||||
},
|
||||
"FieldQuery": "select music.id from music where 1 != 1",
|
||||
"Query": "select music.id from music where music.id in (select music.id from music where music.user_id in (null)) and music.user_id = 5",
|
||||
"Table": "music"
|
||||
},
|
||||
"TablesUsed": [
|
||||
"user.music"
|
||||
|
@ -7668,36 +7326,15 @@ Gen4 plan same as above
|
|||
"QueryType": "SELECT",
|
||||
"Original": "SELECT music.id FROM music WHERE (music.id IN (SELECT music.id FROM music WHERE music.user_id IN (NULL)) OR music.user_id = 5)",
|
||||
"Instructions": {
|
||||
"OperatorType": "Subquery",
|
||||
"Variant": "PulloutIn",
|
||||
"PulloutVars": [
|
||||
"__sq_has_values1",
|
||||
"__sq1"
|
||||
],
|
||||
"Inputs": [
|
||||
{
|
||||
"OperatorType": "Route",
|
||||
"Variant": "None",
|
||||
"Keyspace": {
|
||||
"Name": "user",
|
||||
"Sharded": true
|
||||
},
|
||||
"FieldQuery": "select music.id from music where 1 != 1",
|
||||
"Query": "select music.id from music where music.user_id in (null)",
|
||||
"Table": "music"
|
||||
},
|
||||
{
|
||||
"OperatorType": "Route",
|
||||
"Variant": "Scatter",
|
||||
"Keyspace": {
|
||||
"Name": "user",
|
||||
"Sharded": true
|
||||
},
|
||||
"FieldQuery": "select music.id from music where 1 != 1",
|
||||
"Query": "select music.id from music where :__sq_has_values1 = 1 and music.id in ::__sq1 or music.user_id = 5",
|
||||
"Table": "music"
|
||||
}
|
||||
]
|
||||
"OperatorType": "Route",
|
||||
"Variant": "Scatter",
|
||||
"Keyspace": {
|
||||
"Name": "user",
|
||||
"Sharded": true
|
||||
},
|
||||
"FieldQuery": "select music.id from music where 1 != 1",
|
||||
"Query": "select music.id from music where music.id in (select music.id from music where music.user_id in (null)) or music.user_id = 5",
|
||||
"Table": "music"
|
||||
},
|
||||
"TablesUsed": [
|
||||
"user.music"
|
||||
|
@ -7751,45 +7388,19 @@ Gen4 plan same as above
|
|||
"QueryType": "SELECT",
|
||||
"Original": "SELECT music.id FROM music INNER JOIN (SELECT MAX(id) as maxt FROM music WHERE music.user_id = 5) other ON other.maxt = music.id",
|
||||
"Instructions": {
|
||||
"OperatorType": "Join",
|
||||
"Variant": "Join",
|
||||
"JoinColumnIndexes": "R:0",
|
||||
"JoinVars": {
|
||||
"other_maxt": 0
|
||||
"OperatorType": "Route",
|
||||
"Variant": "EqualUnique",
|
||||
"Keyspace": {
|
||||
"Name": "user",
|
||||
"Sharded": true
|
||||
},
|
||||
"TableName": "music_music",
|
||||
"Inputs": [
|
||||
{
|
||||
"OperatorType": "Route",
|
||||
"Variant": "EqualUnique",
|
||||
"Keyspace": {
|
||||
"Name": "user",
|
||||
"Sharded": true
|
||||
},
|
||||
"FieldQuery": "select 1 from (select max(id) as maxt from music where 1 != 1) as other where 1 != 1",
|
||||
"Query": "select 1 from (select max(id) as maxt from music where music.user_id = 5) as other",
|
||||
"Table": "music",
|
||||
"Values": [
|
||||
"INT64(5)"
|
||||
],
|
||||
"Vindex": "user_index"
|
||||
},
|
||||
{
|
||||
"OperatorType": "Route",
|
||||
"Variant": "EqualUnique",
|
||||
"Keyspace": {
|
||||
"Name": "user",
|
||||
"Sharded": true
|
||||
},
|
||||
"FieldQuery": "select music.id from music where 1 != 1",
|
||||
"Query": "select music.id from music where music.id = :other_maxt",
|
||||
"Table": "music",
|
||||
"Values": [
|
||||
":other_maxt"
|
||||
],
|
||||
"Vindex": "music_user_map"
|
||||
}
|
||||
]
|
||||
"FieldQuery": "select music.id from music, (select max(id) as maxt from music where 1 != 1) as other where 1 != 1",
|
||||
"Query": "select music.id from music, (select max(id) as maxt from music where music.user_id = 5) as other where other.maxt = music.id",
|
||||
"Table": "music",
|
||||
"Values": [
|
||||
"INT64(5)"
|
||||
],
|
||||
"Vindex": "user_index"
|
||||
},
|
||||
"TablesUsed": [
|
||||
"user.music"
|
||||
|
@ -8065,45 +7676,19 @@ Gen4 error: unsupported: JOIN not supported between derived tables
|
|||
"QueryType": "SELECT",
|
||||
"Original": "SELECT music.id FROM (SELECT MAX(id) as maxt FROM music WHERE music.user_id = 5) other JOIN music ON other.maxt = music.id",
|
||||
"Instructions": {
|
||||
"OperatorType": "Join",
|
||||
"Variant": "Join",
|
||||
"JoinColumnIndexes": "R:0",
|
||||
"JoinVars": {
|
||||
"other_maxt": 0
|
||||
"OperatorType": "Route",
|
||||
"Variant": "EqualUnique",
|
||||
"Keyspace": {
|
||||
"Name": "user",
|
||||
"Sharded": true
|
||||
},
|
||||
"TableName": "music_music",
|
||||
"Inputs": [
|
||||
{
|
||||
"OperatorType": "Route",
|
||||
"Variant": "EqualUnique",
|
||||
"Keyspace": {
|
||||
"Name": "user",
|
||||
"Sharded": true
|
||||
},
|
||||
"FieldQuery": "select 1 from (select max(id) as maxt from music where 1 != 1) as other where 1 != 1",
|
||||
"Query": "select 1 from (select max(id) as maxt from music where music.user_id = 5) as other",
|
||||
"Table": "music",
|
||||
"Values": [
|
||||
"INT64(5)"
|
||||
],
|
||||
"Vindex": "user_index"
|
||||
},
|
||||
{
|
||||
"OperatorType": "Route",
|
||||
"Variant": "EqualUnique",
|
||||
"Keyspace": {
|
||||
"Name": "user",
|
||||
"Sharded": true
|
||||
},
|
||||
"FieldQuery": "select music.id from music where 1 != 1",
|
||||
"Query": "select music.id from music where music.id = :other_maxt",
|
||||
"Table": "music",
|
||||
"Values": [
|
||||
":other_maxt"
|
||||
],
|
||||
"Vindex": "music_user_map"
|
||||
}
|
||||
]
|
||||
"FieldQuery": "select music.id from (select max(id) as maxt from music where 1 != 1) as other, music where 1 != 1",
|
||||
"Query": "select music.id from (select max(id) as maxt from music where music.user_id = 5) as other, music where other.maxt = music.id",
|
||||
"Table": "music",
|
||||
"Values": [
|
||||
"INT64(5)"
|
||||
],
|
||||
"Vindex": "user_index"
|
||||
},
|
||||
"TablesUsed": [
|
||||
"user.music"
|
||||
|
|
|
@ -1117,7 +1117,147 @@ Gen4 error: unsupported: cross-shard correlated subquery
|
|||
# TPC-H query 18
|
||||
"select c_name, c_custkey, o_orderkey, o_orderdate, o_totalprice, sum(l_quantity) from customer, orders, lineitem where o_orderkey in ( select l_orderkey from lineitem group by l_orderkey having sum(l_quantity) \u003e 300 ) and c_custkey = o_custkey and o_orderkey = l_orderkey group by c_name, c_custkey, o_orderkey, o_orderdate, o_totalprice order by o_totalprice desc, o_orderdate limit 100"
|
||||
"unsupported: cross-shard query with aggregates"
|
||||
Gen4 error: unsupported: group by on: *planbuilder.joinGen4
|
||||
{
|
||||
"QueryType": "SELECT",
|
||||
"Original": "select c_name, c_custkey, o_orderkey, o_orderdate, o_totalprice, sum(l_quantity) from customer, orders, lineitem where o_orderkey in ( select l_orderkey from lineitem group by l_orderkey having sum(l_quantity) \u003e 300 ) and c_custkey = o_custkey and o_orderkey = l_orderkey group by c_name, c_custkey, o_orderkey, o_orderdate, o_totalprice order by o_totalprice desc, o_orderdate limit 100",
|
||||
"Instructions": {
|
||||
"OperatorType": "Limit",
|
||||
"Count": "INT64(100)",
|
||||
"Inputs": [
|
||||
{
|
||||
"OperatorType": "Aggregate",
|
||||
"Variant": "Ordered",
|
||||
"Aggregates": "sum(5) AS sum(l_quantity)",
|
||||
"GroupBy": "(4|10), (3|9), (0|8), (1|7), (2|6)",
|
||||
"ResultColumns": 6,
|
||||
"Inputs": [
|
||||
{
|
||||
"OperatorType": "Projection",
|
||||
"Expressions": [
|
||||
"[COLUMN 2] as c_name",
|
||||
"[COLUMN 3] as c_custkey",
|
||||
"[COLUMN 4] as o_orderkey",
|
||||
"[COLUMN 1] as o_orderdate",
|
||||
"[COLUMN 0] as o_totalprice",
|
||||
"([COLUMN 10] * [COLUMN 11]) * [COLUMN 12] as sum(l_quantity)",
|
||||
"[COLUMN 9]",
|
||||
"[COLUMN 8]",
|
||||
"[COLUMN 7]",
|
||||
"[COLUMN 6]",
|
||||
"[COLUMN 5]"
|
||||
],
|
||||
"Inputs": [
|
||||
{
|
||||
"OperatorType": "Join",
|
||||
"Variant": "Join",
|
||||
"JoinColumnIndexes": "L:2,L:3,L:4,L:5,L:6,L:8,L:9,L:10,L:11,L:12,L:13,L:14,R:1",
|
||||
"JoinVars": {
|
||||
"o_orderkey": 0
|
||||
},
|
||||
"TableName": "orders_customer_lineitem",
|
||||
"Inputs": [
|
||||
{
|
||||
"OperatorType": "Sort",
|
||||
"Variant": "Memory",
|
||||
"OrderBy": "(2|8) DESC, (3|9) ASC, (4|10) ASC, (5|11) ASC, (0|7) ASC",
|
||||
"Inputs": [
|
||||
{
|
||||
"OperatorType": "Join",
|
||||
"Variant": "Join",
|
||||
"JoinColumnIndexes": "L:1,L:1,L:5,L:7,R:1,R:3,L:1,L:4,L:6,L:8,R:2,R:4,L:4,L:2,R:0",
|
||||
"JoinVars": {
|
||||
"o_custkey": 0
|
||||
},
|
||||
"TableName": "orders_customer",
|
||||
"Inputs": [
|
||||
{
|
||||
"OperatorType": "Route",
|
||||
"Variant": "IN",
|
||||
"Keyspace": {
|
||||
"Name": "main",
|
||||
"Sharded": true
|
||||
},
|
||||
"FieldQuery": "select o_custkey, o_orderkey, count(*), weight_string(o_custkey), weight_string(o_orderkey), o_totalprice, weight_string(o_totalprice), o_orderdate, weight_string(o_orderdate) from orders where 1 != 1 group by o_custkey, weight_string(o_custkey), o_orderkey, weight_string(o_orderkey), o_totalprice, weight_string(o_totalprice), o_orderdate, weight_string(o_orderdate)",
|
||||
"Query": "select o_custkey, o_orderkey, count(*), weight_string(o_custkey), weight_string(o_orderkey), o_totalprice, weight_string(o_totalprice), o_orderdate, weight_string(o_orderdate) from orders where :o_orderkey in (select l_orderkey from lineitem group by l_orderkey having sum(l_quantity) \u003e 300) group by o_custkey, weight_string(o_custkey), o_orderkey, weight_string(o_orderkey), o_totalprice, weight_string(o_totalprice), o_orderdate, weight_string(o_orderdate)",
|
||||
"Table": "orders",
|
||||
"Values": [
|
||||
":__sq1"
|
||||
],
|
||||
"Vindex": "hash"
|
||||
},
|
||||
{
|
||||
"OperatorType": "Route",
|
||||
"Variant": "EqualUnique",
|
||||
"Keyspace": {
|
||||
"Name": "main",
|
||||
"Sharded": true
|
||||
},
|
||||
"FieldQuery": "select count(*), c_name, weight_string(c_name), c_custkey, weight_string(c_custkey) from customer where 1 != 1 group by c_name, weight_string(c_name), c_custkey, weight_string(c_custkey)",
|
||||
"Query": "select count(*), c_name, weight_string(c_name), c_custkey, weight_string(c_custkey) from customer where c_custkey = :o_custkey group by c_name, weight_string(c_name), c_custkey, weight_string(c_custkey)",
|
||||
"Table": "customer",
|
||||
"Values": [
|
||||
":o_custkey"
|
||||
],
|
||||
"Vindex": "hash"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"OperatorType": "VindexLookup",
|
||||
"Variant": "EqualUnique",
|
||||
"Keyspace": {
|
||||
"Name": "main",
|
||||
"Sharded": true
|
||||
},
|
||||
"Values": [
|
||||
":o_orderkey"
|
||||
],
|
||||
"Vindex": "lineitem_map",
|
||||
"Inputs": [
|
||||
{
|
||||
"OperatorType": "Route",
|
||||
"Variant": "IN",
|
||||
"Keyspace": {
|
||||
"Name": "main",
|
||||
"Sharded": true
|
||||
},
|
||||
"FieldQuery": "select l_orderkey, l_linenumber from lineitem_map where 1 != 1",
|
||||
"Query": "select l_orderkey, l_linenumber from lineitem_map where l_orderkey in ::__vals",
|
||||
"Table": "lineitem_map",
|
||||
"Values": [
|
||||
":l_orderkey"
|
||||
],
|
||||
"Vindex": "md5"
|
||||
},
|
||||
{
|
||||
"OperatorType": "Route",
|
||||
"Variant": "ByDestination",
|
||||
"Keyspace": {
|
||||
"Name": "main",
|
||||
"Sharded": true
|
||||
},
|
||||
"FieldQuery": "select 1, sum(l_quantity) from lineitem where 1 != 1 group by 1",
|
||||
"Query": "select 1, sum(l_quantity) from lineitem where l_orderkey = :o_orderkey group by 1",
|
||||
"Table": "lineitem"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"TablesUsed": [
|
||||
"main.customer",
|
||||
"main.lineitem",
|
||||
"main.orders"
|
||||
]
|
||||
}
|
||||
|
||||
# TPC-H query 19
|
||||
"select sum(l_extendedprice* (1 - l_discount)) as revenue from lineitem, part where ( p_partkey = l_partkey and p_brand = 'Brand#12' and p_container in ('SM CASE', 'SM BOX', 'SM PACK', 'SM PKG') and l_quantity \u003e= 1 and l_quantity \u003c= 1 + 10 and p_size between 1 and 5 and l_shipmode in ('AIR', 'AIR REG') and l_shipinstruct = 'DELIVER IN PERSON' ) or ( p_partkey = l_partkey and p_brand = 'Brand#23' and p_container in ('MED BAG', 'MED BOX', 'MED PKG', 'MED PACK') and l_quantity \u003e= 10 and l_quantity \u003c= 10 + 10 and p_size between 1 and 10 and l_shipmode in ('AIR', 'AIR REG') and l_shipinstruct = 'DELIVER IN PERSON' ) or ( p_partkey = l_partkey and p_brand = 'Brand#34' and p_container in ('LG CASE', 'LG BOX', 'LG PACK', 'LG PKG') and l_quantity \u003e= 20 and l_quantity \u003c= 20 + 10 and p_size between 1 and 15 and l_shipmode in ('AIR', 'AIR REG') and l_shipinstruct = 'DELIVER IN PERSON' )"
|
||||
|
|
Загрузка…
Ссылка в новой задаче