ORDER BY NULL is a special-case construct that serves as hint
to the optimizer that the client is not expecting the result
in any particular order. So, it's safe to push it down to
all routes without regard to relational rules.
This commit is contained in:
Sugu Sougoumarane 2016-11-25 17:10:51 -08:00 коммит произвёл sougou
Родитель 630d76b100
Коммит 5a44ded295
7 изменённых файлов: 86 добавлений и 1 удалений

Просмотреть файл

@ -208,6 +208,21 @@
}
}
# ORDER BY NULL
"select col from user order by null"
{
"Original": "select col from user order by null",
"Instructions": {
"Opcode": "SelectScatter",
"Keyspace": {
"Name": "user",
"Sharded": true
},
"Query": "select col from user order by null",
"FieldQuery": "select col from user where 1 != 1"
}
}
# ORDER BY for join
"select user.col1 as a, user.col2, music.col3 from user join music on user.id = music.id where user.id = 1 order by a asc, user.col2 desc, music.col3 asc"
{
@ -250,6 +265,48 @@
}
}
# ORDER BY NULL for join
"select user.col1 as a, user.col2, music.col3 from user join music on user.id = music.id where user.id = 1 order by null"
{
"Original": "select user.col1 as a, user.col2, music.col3 from user join music on user.id = music.id where user.id = 1 order by null",
"Instructions": {
"Opcode": "Join",
"Left": {
"Opcode": "SelectEqualUnique",
"Keyspace": {
"Name": "user",
"Sharded": true
},
"Query": "select user.col1 as a, user.col2, user.id from user where user.id = 1 order by null",
"FieldQuery": "select user.col1 as a, user.col2, user.id from user where 1 != 1",
"Vindex": "user_index",
"Values": 1
},
"Right": {
"Opcode": "SelectEqualUnique",
"Keyspace": {
"Name": "user",
"Sharded": true
},
"Query": "select music.col3 from music where music.id = :user_id order by null",
"FieldQuery": "select music.col3 from music where 1 != 1",
"Vindex": "music_user_map",
"Values": ":user_id",
"JoinVars": {
"user_id": {}
}
},
"Cols": [
-1,
-2,
1
],
"Vars": {
"user_id": 2
}
}
}
# ORDER BY for join, using column numbers
"select user.col1 as a, user.col2, music.col3 from user join music on user.id = music.id where user.id = 1 order by 1 asc, 2 desc, 3 asc"
{

Просмотреть файл

@ -1594,6 +1594,10 @@ const (
// Format formats the node.
func (node *Order) Format(buf *TrackedBuffer) {
if node, ok := node.Expr.(*NullVal); ok {
buf.Myprintf("%v", node)
return
}
buf.Myprintf("%v %s", node.Expr, node.Direction)
}

Просмотреть файл

@ -397,6 +397,8 @@ func TestValid(t *testing.T) {
input: "select /* order by asc */ 1 from t order by a asc",
}, {
input: "select /* order by desc */ 1 from t order by a desc",
}, {
input: "select /* order by null */ 1 from t order by null",
}, {
input: "select /* limit a */ 1 from t limit a",
}, {

Просмотреть файл

@ -50,6 +50,10 @@ type builder interface {
// column. The function must return a colsym for the expression
// and the column number of the result.
PushSelect(expr *sqlparser.NonStarExpr, rb *route) (colsym *colsym, colnum int, err error)
// PushOrderByNull pushes the special case ORDER By NULL to
// all routes. It's safe to push down this clause because it's
// just on optimization hint.
PushOrderByNull()
// PushMisc pushes miscelleaneous constructs to all the routes.
// This should not propagate to subqueries.
PushMisc(sel *sqlparser.Select)

Просмотреть файл

@ -140,6 +140,12 @@ func (jb *join) PushSelect(expr *sqlparser.NonStarExpr, rb *route) (colsym *cols
return colsym, len(jb.Colsyms) - 1, nil
}
// PushOrderByNull pushes misc constructs to the underlying routes.
func (jb *join) PushOrderByNull() {
jb.Left.PushOrderByNull()
jb.Right.PushOrderByNull()
}
// PushMisc pushes misc constructs to the underlying routes.
func (jb *join) PushMisc(sel *sqlparser.Select) {
jb.Left.PushMisc(sel)

Просмотреть файл

@ -73,8 +73,15 @@ func pushOrderBy(orderBy sqlparser.OrderBy, bldr builder) error {
s := bldr.Symtab().SetState(symtabOrderBy)
defer bldr.Symtab().SetState(s)
if orderBy == nil {
switch len(orderBy) {
case 0:
return nil
case 1:
// Special handling for ORDER BY NULL. Push it everywhere.
if _, ok := orderBy[0].Expr.(*sqlparser.NullVal); ok {
bldr.PushOrderByNull()
return nil
}
}
routeNumber := 0
for _, order := range orderBy {

Просмотреть файл

@ -386,6 +386,11 @@ func (rb *route) SetLimit(limit *sqlparser.Limit) {
rb.Select.Limit = limit
}
// PushOrderByNull updates the comments & 'for update' sections of the route.
func (rb *route) PushOrderByNull() {
rb.Select.OrderBy = sqlparser.OrderBy{&sqlparser.Order{Expr: &sqlparser.NullVal{}}}
}
// PushMisc updates the comments & 'for update' sections of the route.
func (rb *route) PushMisc(sel *sqlparser.Select) {
rb.Select.Comments = sel.Comments