func (e *XSelectIndexExec) doTableRequest(handles []int64) (distsql.SelectResult, error) { // The handles are not in original index order, so we can't push limit here. selTableReq := new(tipb.SelectRequest) if e.indexPlan.OutOfOrder { selTableReq.Limit = e.indexPlan.LimitCount } selTableReq.StartTs = e.startTS selTableReq.TimeZoneOffset = proto.Int64(timeZoneOffset()) selTableReq.TableInfo = &tipb.TableInfo{ TableId: e.table.Meta().ID, } selTableReq.TableInfo.Columns = distsql.ColumnsToProto(e.indexPlan.Columns, e.table.Meta().PKIsHandle) selTableReq.Where = e.where // Aggregate Info selTableReq.Aggregates = e.aggFuncs selTableReq.GroupBy = e.byItems keyRanges := tableHandlesToKVRanges(e.table.Meta().ID, handles) concurrency, err := getScanConcurrency(e.ctx) if err != nil { return nil, errors.Trace(err) } resp, err := distsql.Select(e.ctx.GetClient(), selTableReq, keyRanges, concurrency, false) if err != nil { return nil, errors.Trace(err) } if e.aggregate { // The returned rows should be aggregate partial result. resp.SetFields(e.aggFields) } resp.Fetch() return resp, nil }
// doRequest sends a *tipb.SelectRequest via kv.Client and gets the distsql.SelectResult. func (e *XSelectTableExec) doRequest() error { var err error selReq := new(tipb.SelectRequest) selReq.StartTs = e.startTS selReq.TimeZoneOffset = timeZoneOffset() selReq.Flags = statementContextToFlags(e.ctx.GetSessionVars().StmtCtx) selReq.Where = e.where selReq.TableInfo = &tipb.TableInfo{ TableId: e.tableInfo.ID, Columns: distsql.ColumnsToProto(e.Columns, e.tableInfo.PKIsHandle), } if len(e.orderByList) > 0 { selReq.OrderBy = e.orderByList } else if e.supportDesc && e.desc { selReq.OrderBy = []*tipb.ByItem{{Desc: e.desc}} } selReq.Limit = e.limitCount // Aggregate Info selReq.Aggregates = e.aggFuncs selReq.GroupBy = e.byItems kvRanges := tableRangesToKVRanges(e.table.Meta().ID, e.ranges) concurrency := e.scanConcurrency e.result, err = distsql.Select(e.ctx.GetClient(), selReq, kvRanges, concurrency, e.keepOrder) if err != nil { return errors.Trace(err) } //if len(selReq.Aggregates) > 0 || len(selReq.GroupBy) > 0 { if e.aggregate { // The returned rows should be aggregate partial result. e.result.SetFields(e.aggFields) } e.result.Fetch() return nil }
func (e *XSelectIndexExec) doIndexRequest() (distsql.SelectResult, error) { selIdxReq := new(tipb.SelectRequest) selIdxReq.StartTs = e.startTS selIdxReq.TimeZoneOffset = proto.Int64(timeZoneOffset()) selIdxReq.IndexInfo = distsql.IndexToProto(e.table.Meta(), e.indexPlan.Index) if len(e.indexPlan.SortItems) > 0 { selIdxReq.OrderBy = e.indexPlan.SortItems } else if e.indexPlan.Desc { selIdxReq.OrderBy = []*tipb.ByItem{{Desc: e.indexPlan.Desc}} } if e.singleReadMode || e.where == nil { // TODO: when where condition is all index columns limit can be pushed too. selIdxReq.Limit = e.indexPlan.LimitCount } concurrency, err := getScanConcurrency(e.ctx) if err != nil { return nil, errors.Trace(err) } if e.singleReadMode { selIdxReq.Aggregates = e.aggFuncs selIdxReq.GroupBy = e.byItems selIdxReq.Where = e.where } else if !e.indexPlan.OutOfOrder { // The cost of index scan double-read is higher than single-read. Usually ordered index scan has a limit // which may not have been pushed down, so we set concurrency to 1 to avoid fetching unnecessary data. concurrency = 1 } fieldTypes := make([]*types.FieldType, len(e.indexPlan.Index.Columns)) for i, v := range e.indexPlan.Index.Columns { fieldTypes[i] = &(e.table.Cols()[v.Offset].FieldType) } keyRanges, err := indexRangesToKVRanges(e.table.Meta().ID, e.indexPlan.Index.ID, e.indexPlan.Ranges, fieldTypes) if err != nil { return nil, errors.Trace(err) } return distsql.Select(e.ctx.GetClient(), selIdxReq, keyRanges, concurrency, !e.indexPlan.OutOfOrder) }