Example #1
0
// 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)
}
Example #2
0
// 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()
}