예제 #1
0
func (this *builder) buildSecondaryScan(secondaries map[datastore.Index]*indexEntry,
	node *algebra.KeyspaceTerm, limit expression.Expression) (plan.Operator, error) {
	if this.cover != nil {
		scan, err := this.buildCoveringScan(secondaries, node, limit)
		if scan != nil || err != nil {
			return scan, err
		}
	}

	scans := make([]plan.Operator, 0, len(secondaries))
	var op plan.Operator
	for index, entry := range secondaries {
		op = plan.NewIndexScan(index, node, entry.spans, false, limit, nil)
		if len(entry.spans) > 1 {
			// Use UnionScan to de-dup multiple spans
			op = plan.NewUnionScan(op)
		} else {
			// Use UnionScan to de-dup array index scans
			for _, sk := range entry.sargKeys {
				if isArray, _ := sk.IsArrayIndexKey(); isArray {
					op = plan.NewUnionScan(op)
					break
				}
			}
		}

		scans = append(scans, op)
	}

	if len(scans) > 1 {
		return plan.NewIntersectScan(scans...), nil
	} else {
		return scans[0], nil
	}
}
예제 #2
0
func (this *builder) buildCoveringScan(secondaries map[datastore.Index]*indexEntry,
	node *algebra.KeyspaceTerm, limit expression.Expression) (plan.Operator, error) {
	if this.cover == nil {
		return nil, nil
	}

	alias := node.Alias()
	exprs := this.cover.Expressions()
	id := expression.NewField(
		expression.NewMeta(expression.NewIdentifier(node.Alias())),
		expression.NewFieldName("id", false))

outer:
	for index, entry := range secondaries {
		keys := entry.keys
		if !index.IsPrimary() {
			// Matches execution.spanScan.RunOnce()
			keys = append(keys, id)
		}

		// Use the first available covering index
		for _, expr := range exprs {
			if !expr.CoveredBy(alias, keys) {
				continue outer
			}
		}

		covers := make(expression.Covers, 0, len(keys))
		for _, key := range keys {
			covers = append(covers, expression.NewCover(key))
		}

		scan := plan.NewIndexScan(index, node, entry.spans, false, limit, covers)
		this.coveringScan = scan

		if len(entry.spans) > 1 {
			// Use UnionScan to de-dup multiple spans
			return plan.NewUnionScan(scan), nil
		}

		return scan, nil
	}

	return nil, nil
}