// SplitQueryV2 splits a query + bind variables into smaller queries that return a // subset of rows from the original query. This is the new version that supports multiple // split columns and multiple split algortihms. // See the documentation of SplitQueryRequest in proto/vtgate.proto for more details. func (tsv *TabletServer) SplitQueryV2( ctx context.Context, target *querypb.Target, sql string, bindVariables map[string]interface{}, splitColumns []string, splitCount int64, numRowsPerQueryPart int64, algorithm querypb.SplitQueryRequest_Algorithm, ) (splits []querytypes.QuerySplit, err error) { logStats := newLogStats("SplitQuery", ctx) logStats.OriginalSQL = sql logStats.BindVariables = bindVariables defer handleError(&err, logStats, tsv.qe.queryServiceStats) if err = tsv.startRequest(target, false, false); err != nil { return nil, err } // We don't set a timeout for SplitQueryV2. // SplitQuery using the Full Scan algorithm can take a while and // we don't expect too many of these queries to run concurrently. defer tsv.endRequest(false) ciSplitColumns := make([]sqlparser.ColIdent, 0, len(splitColumns)) for _, s := range splitColumns { ciSplitColumns = append(ciSplitColumns, sqlparser.NewColIdent(s)) } if err := validateSplitQueryParameters( target, sql, bindVariables, splitColumns, splitCount, numRowsPerQueryPart, algorithm, ); err != nil { return nil, err } schema := getSchemaForSplitQuery(tsv.qe.schemaInfo) splitParams, err := createSplitParams( sql, bindVariables, ciSplitColumns, splitCount, numRowsPerQueryPart, schema) if err != nil { return nil, err } defer func(start time.Time) { splitTableName := splitParams.GetSplitTableName() addUserTableQueryStats( tsv.qe.queryServiceStats, ctx, splitTableName, "SplitQuery", int64(time.Now().Sub(start))) }(time.Now()) sqlExecuter, err := newSplitQuerySQLExecuter(ctx, logStats, tsv.qe) if err != nil { return nil, err } defer sqlExecuter.done() algorithmObject, err := createSplitQueryAlgorithmObject(algorithm, splitParams, sqlExecuter) if err != nil { return nil, err } result, err := splitquery.NewSplitter(splitParams, algorithmObject).Split() return result, splitQueryToTabletError(err) }
// SplitQueryV2 splits a query + bind variables into smaller queries that return a // subset of rows from the original query. This is the new version that supports multiple // split columns and multiple split algortihms. // See the documentation of SplitQueryRequest in proto/vtgate.proto for more details. func (tsv *TabletServer) SplitQueryV2( ctx context.Context, target *querypb.Target, sql string, bindVariables map[string]interface{}, splitColumns []string, splitCount int64, numRowsPerQueryPart int64, algorithm querypb.SplitQueryRequest_Algorithm, sessionID int64) (splits []querytypes.QuerySplit, err error) { if err := validateSplitQueryParameters( sql, bindVariables, splitColumns, splitCount, numRowsPerQueryPart, algorithm, sessionID); err != nil { return nil, err } // TODO(erez): ASSERT/Check that we are a rdonly tablet. logStats := newLogStats("SplitQuery", ctx) logStats.OriginalSQL = sql logStats.BindVariables = bindVariables defer handleError(&err, logStats, tsv.qe.queryServiceStats) if err = tsv.startRequest(target, sessionID, false, false); err != nil { return nil, err } ctx, cancel := withTimeout(ctx, tsv.QueryTimeout.Get()) defer func() { cancel() tsv.endRequest(false) }() schema := getSchemaForSplitQuery(tsv.qe.schemaInfo) var splitParams *splitquery.SplitParams switch { case numRowsPerQueryPart != 0 && splitCount == 0: splitParams, err = splitquery.NewSplitParamsGivenNumRowsPerQueryPart( sql, bindVariables, splitColumns, numRowsPerQueryPart, schema) case numRowsPerQueryPart == 0 && splitCount != 0: splitParams, err = splitquery.NewSplitParamsGivenSplitCount( sql, bindVariables, splitColumns, splitCount, schema) default: panic(fmt.Sprintf("Exactly one of {numRowsPerQueryPart, splitCount} must be"+ " non zero. This should have already been caught by 'validateSplitQueryParameters' and "+ " returned as an error. Got: numRowsPerQueryPart=%v, splitCount=%v. SQL: %v", numRowsPerQueryPart, splitCount, querytypes.QueryAsString(sql, bindVariables))) } // TODO(erez): Make the splitquery package return tabletserver errors. if err != nil { return nil, err } defer func(start time.Time) { addUserTableQueryStats( tsv.qe.queryServiceStats, ctx, splitParams.GetSplitTableName(), "SplitQuery", int64(time.Now().Sub(start))) }(time.Now()) sqlExecuter := &splitQuerySQLExecuter{ queryExecutor: &QueryExecutor{ ctx: ctx, logStats: logStats, qe: tsv.qe, }, } algorithmObject, err := createSplitQueryAlgorithmObject(algorithm, splitParams, sqlExecuter) if err != nil { return nil, err } // TODO(erez): Make the splitquery package use Vitess error codes. return splitquery.NewSplitter(splitParams, algorithmObject).Split() }