Beispiel #1
0
        IList <PackedObject> ProcessAndQuery(AndQuery query, ExecutionPlan executionPlan)
        {
            if (query.Elements.Count == 1)
            {
                return(ProcessSimpleQuery(query.Elements[0], executionPlan));
            }

            var queryExecutionPlan = new QueryExecutionPlan(query.ToString());

            // this method can be called in parallel. The only common data is the global execution plan
            lock (executionPlan)
            {
                executionPlan.QueryPlans.Add(queryExecutionPlan);
            }


            queryExecutionPlan.StartPlanning();
            var indexesToUse = GetIndexesForQuery(query);

            queryExecutionPlan.EndPlanning();

            // this will contain all queries that have can not be resolved by indexes and need to be checked manually
            var restOfTheQuery = query.Clone();

            ISet <PackedObject> result = null;

            var finalResult = new List <PackedObject>();



            if (indexesToUse.Count == 1) // only one index can be used so do not bother with extra logic
            {
                queryExecutionPlan.StartIndexUse();
                var plan = indexesToUse[0];

                queryExecutionPlan.Trace($"single index: {plan.ResolvedQuery.PropertyName}");

                result = plan.Index.GetMany(plan.ResolvedQuery.Values, plan.ResolvedQuery.Operator);

                // this query was resolved by an index so no need to check it manually
                restOfTheQuery.Elements.Remove(plan.ResolvedQuery);

                queryExecutionPlan.EndIndexUse();
            }
            else if (indexesToUse.Count > 1)
            {
                queryExecutionPlan.StartIndexUse();

                foreach (var plan in indexesToUse.OrderBy(p => p.Ranking).Take(2)) // no more than two indexes
                {
                    if (result == null)
                    {
                        result = plan.Index.GetMany(plan.ResolvedQuery.Values, plan.ResolvedQuery.Operator);
                        queryExecutionPlan.Trace($"first index: {plan.ResolvedQuery.PropertyName} = {plan.Ranking}");
                    }
                    else
                    {
                        result.IntersectWith(plan.Index.GetMany(plan.ResolvedQuery.Values, plan.ResolvedQuery.Operator));
                        queryExecutionPlan.Trace($"then index: {plan.ResolvedQuery.PropertyName} = {plan.Ranking} => {result.Count}");
                    }

                    // do not work too hard if indexes found nothing
                    if (result.Count == 0)
                    {
                        break;
                    }

                    // this query was resolved by an index so no need to check it manually
                    restOfTheQuery.Elements.Remove(plan.ResolvedQuery);
                }

                queryExecutionPlan.EndIndexUse();
            }
            else // no index can be used so proceed to full-scan
            {
                queryExecutionPlan.FullScan = true;

                queryExecutionPlan.StartScan();
                var res = _dataStore.PrimaryIndex.GetAll().Where(o => restOfTheQuery.Match(o)).ToList();
                queryExecutionPlan.EndScan();

                return(res);
            }


            if (result != null)
            {
                if (restOfTheQuery.Elements.Count == 0) // empty query left; fully resolved by indexes
                {
                    return(result.ToList());
                }

                queryExecutionPlan.StartScan();

                foreach (var item in result)
                {
                    if (restOfTheQuery.Match(item))
                    {
                        finalResult.Add(item);
                    }
                }

                queryExecutionPlan.EndScan();
            }


            return(finalResult);
        }