-
Notifications
You must be signed in to change notification settings - Fork 5.9k
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
*: fast path point select #6937
Changes from 8 commits
2198b32
e855838
699b34b
e5adb09
9c01155
4942f47
0971fff
171daed
a183771
55757cd
01be667
4bb52a0
b4843e9
5b4f1b3
fd96ed9
aaad31e
050235d
74fc80d
f0ff662
c8e64d5
b8598b2
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,186 @@ | ||
// Copyright 2018 PingCAP, Inc. | ||
// | ||
// Licensed under the Apache License, Version 2.0 (the "License"); | ||
// you may not use this file except in compliance with the License. | ||
// You may obtain a copy of the License at | ||
// | ||
// http://www.apache.org/licenses/LICENSE-2.0 | ||
// | ||
// Unless required by applicable law or agreed to in writing, software | ||
// distributed under the License is distributed on an "AS IS" BASIS, | ||
// See the License for the specific language governing permissions and | ||
// limitations under the License. | ||
|
||
package executor | ||
|
||
import ( | ||
"github.com/juju/errors" | ||
"github.com/pingcap/tidb/expression" | ||
"github.com/pingcap/tidb/kv" | ||
"github.com/pingcap/tidb/model" | ||
"github.com/pingcap/tidb/mysql" | ||
"github.com/pingcap/tidb/plan" | ||
"github.com/pingcap/tidb/sessionctx" | ||
"github.com/pingcap/tidb/table" | ||
"github.com/pingcap/tidb/table/tables" | ||
"github.com/pingcap/tidb/tablecodec" | ||
"github.com/pingcap/tidb/types" | ||
"github.com/pingcap/tidb/util/chunk" | ||
"github.com/pingcap/tidb/util/codec" | ||
"golang.org/x/net/context" | ||
) | ||
|
||
func (b *executorBuilder) buildPointSelect(p *plan.PointSelectPlan) Executor { | ||
return &PointSelectExecutor{ | ||
ctx: b.ctx, | ||
schema: p.Schema(), | ||
tblInfo: p.TblInfo, | ||
idxInfo: p.IndexInfo, | ||
idxVals: p.IndexValues, | ||
handle: p.Handle, | ||
startTS: b.getStartTS(), | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why not use There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The statement may be UPDATE/DELETE or in an explicit transaction. |
||
} | ||
} | ||
|
||
// PointSelectExecutor executes point select query. | ||
type PointSelectExecutor struct { | ||
ctx sessionctx.Context | ||
schema *expression.Schema | ||
tps []*types.FieldType | ||
tblInfo *model.TableInfo | ||
handle int64 | ||
idxInfo *model.IndexInfo | ||
idxVals []types.Datum | ||
startTS uint64 | ||
snapshot kv.Snapshot | ||
done bool | ||
} | ||
|
||
// Open implements the Executor interface. | ||
func (e *PointSelectExecutor) Open(context.Context) error { | ||
return nil | ||
} | ||
|
||
// Close implements the Executor interface. | ||
func (e *PointSelectExecutor) Close() error { | ||
return nil | ||
} | ||
|
||
// Next implements the Executor interface. | ||
func (e *PointSelectExecutor) Next(ctx context.Context, chk *chunk.Chunk) error { | ||
chk.Reset() | ||
if e.done { | ||
return nil | ||
} | ||
e.done = true | ||
snapshot, err1 := e.ctx.GetStore().GetSnapshot(kv.Version{Ver: e.startTS}) | ||
if err1 != nil { | ||
return errors.Trace(err1) | ||
} | ||
e.snapshot = snapshot | ||
if e.idxInfo != nil { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
for i := range e.idxVals { | ||
colInfo := e.tblInfo.Columns[e.idxInfo.Columns[i].Offset] | ||
casted, err := table.CastValue(e.ctx, e.idxVals[i], colInfo) | ||
if err != nil { | ||
return errors.Trace(err) | ||
} | ||
e.idxVals[i] = casted | ||
} | ||
encodedIdxVals, err := codec.EncodeKey(e.ctx.GetSessionVars().StmtCtx, nil, e.idxVals...) | ||
if err != nil { | ||
return errors.Trace(err) | ||
} | ||
idxKey := tablecodec.EncodeIndexSeekKey(e.tblInfo.ID, e.idxInfo.ID, encodedIdxVals) | ||
handleVal, err := e.get(idxKey) | ||
if err != nil && !kv.ErrNotExist.Equal(err) { | ||
return errors.Trace(err) | ||
} | ||
if len(handleVal) == 0 { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. When will this happen? Is it equal to There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. When the key is deleted, it can be found in mem buffer but |
||
return nil | ||
} | ||
h, err := tables.DecodeHandle(handleVal) | ||
if err != nil { | ||
return errors.Trace(err) | ||
} | ||
e.handle = h | ||
} | ||
key := tablecodec.EncodeRowKeyWithHandle(e.tblInfo.ID, e.handle) | ||
val, err := e.get(key) | ||
if err != nil && !kv.ErrNotExist.Equal(err) { | ||
return errors.Trace(err) | ||
} | ||
if len(val) == 0 { | ||
return nil | ||
} | ||
colIDs := make(map[int64]int) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The following code can also be extracted to a function
|
||
for i, col := range e.schema.Columns { | ||
colIDs[col.ID] = i | ||
} | ||
colVals, err := tablecodec.CutRowNew(val, colIDs) | ||
if err != nil { | ||
return errors.Trace(err) | ||
} | ||
decoder := codec.NewDecoder(chk, e.ctx.GetSessionVars().Location()) | ||
for id, offset := range colIDs { | ||
if e.tblInfo.PKIsHandle && mysql.HasPriKeyFlag(e.schema.Columns[offset].RetType.Flag) { | ||
chk.AppendInt64(offset, e.handle) | ||
continue | ||
} | ||
if id == model.ExtraHandleID { | ||
chk.AppendInt64(offset, e.handle) | ||
continue | ||
} | ||
colVal := colVals[offset] | ||
if len(colVal) == 0 { | ||
colInfo := getColInfoByID(e.tblInfo, id) | ||
d, err1 := table.GetColOriginDefaultValue(e.ctx, colInfo) | ||
if err1 != nil { | ||
return errors.Trace(err1) | ||
} | ||
chk.AppendDatum(offset, &d) | ||
continue | ||
} | ||
_, err = decoder.DecodeOne(colVals[offset], offset, e.schema.Columns[offset].RetType) | ||
if err != nil { | ||
return errors.Trace(err) | ||
} | ||
} | ||
return nil | ||
} | ||
|
||
func (e *PointSelectExecutor) get(key kv.Key) (val []byte, err error) { | ||
txn := e.ctx.Txn() | ||
if txn != nil && txn.Valid() && !txn.IsReadOnly() { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. When will this happen? PointUpdate? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes |
||
return txn.Get(key) | ||
} | ||
return e.snapshot.Get(key) | ||
} | ||
|
||
func getColInfoByID(tbl *model.TableInfo, colID int64) *model.ColumnInfo { | ||
for _, col := range tbl.Columns { | ||
if col.ID == colID { | ||
return col | ||
} | ||
} | ||
return nil | ||
} | ||
|
||
// Schema implements the Executor interface. | ||
func (e *PointSelectExecutor) Schema() *expression.Schema { | ||
return e.schema | ||
} | ||
|
||
func (e *PointSelectExecutor) retTypes() []*types.FieldType { | ||
if e.tps == nil { | ||
e.tps = make([]*types.FieldType, e.schema.Len()) | ||
for i := range e.schema.Columns { | ||
e.tps[i] = e.schema.Columns[i].RetType | ||
} | ||
} | ||
return e.tps | ||
} | ||
|
||
func (e *PointSelectExecutor) newChunk() *chunk.Chunk { | ||
return chunk.NewChunkWithCapacity(e.retTypes(), 1) | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -1581,8 +1581,6 @@ func (s *testIntegrationSuite) TestTimeBuiltin(c *C) { | |
// TODO: MySQL returns "<nil> <nil>". | ||
result.Check(testkit.Rows("0000-00-01 <nil>")) | ||
tk.MustQuery("show warnings").Check(testutil.RowsWithSep("|", "Warning|1292|Incorrect datetime value: '0000-00-00 00:00:00'")) | ||
result = tk.MustQuery("select str_to_date('2018-6-1', '%Y-%m-%d'), str_to_date('2018-6-1', '%Y-%c-%d'), str_to_date('59:20:1', '%s:%i:%k'), str_to_date('59:20:1', '%s:%i:%l')") | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I wonder why it's removed? |
||
result.Check(testkit.Rows("2018-06-01 2018-06-01 01:20:59 01:20:59")) | ||
|
||
// for maketime | ||
tk.MustExec(`drop table if exists t`) | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why make this change?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
go lint reports error because it returns an unexported type
statsInfo
.