Search in sources :

Example 1 with OSizeable

use of com.orientechnologies.common.util.OSizeable in project orientdb by orientechnologies.

the class OCommandExecutorSQLSelect method searchForIndexes.

@SuppressWarnings("rawtypes")
private boolean searchForIndexes(final OClass iSchemaClass) {
    if (uniqueResult != null)
        uniqueResult.clear();
    final ODatabaseDocument database = getDatabase();
    database.checkSecurity(ORule.ResourceGeneric.CLASS, ORole.PERMISSION_READ, iSchemaClass.getName().toLowerCase());
    // fetch all possible variants of subqueries that can be used in indexes.
    if (compiledFilter == null) {
        return tryOptimizeSort(iSchemaClass);
    }
    // try indexed functions
    Iterator<OIdentifiable> fetchedFromFunction = tryIndexedFunctions(iSchemaClass);
    if (fetchedFromFunction != null) {
        fetchFromTarget(fetchedFromFunction);
        return true;
    }
    // the main condition is a set of sub-conditions separated by OR operators
    final List<List<OIndexSearchResult>> conditionHierarchy = filterAnalyzer.analyzeMainCondition(compiledFilter.getRootCondition(), iSchemaClass, context);
    if (conditionHierarchy == null)
        return false;
    List<OIndexCursor> cursors = new ArrayList<OIndexCursor>();
    boolean indexIsUsedInOrderBy = false;
    List<IndexUsageLog> indexUseAttempts = new ArrayList<IndexUsageLog>();
    try {
        //to track if the index used is specific for this class or if it's defined on a super/sub class
        boolean indexOnExactClass = true;
        OIndexSearchResult lastSearchResult = null;
        for (List<OIndexSearchResult> indexSearchResults : conditionHierarchy) {
            // go through all variants to choose which one can be used for index search.
            boolean indexUsed = false;
            for (final OIndexSearchResult searchResult : indexSearchResults) {
                lastSearchResult = searchResult;
                final List<OIndex<?>> involvedIndexes = filterAnalyzer.getInvolvedIndexes(iSchemaClass, searchResult);
                Collections.sort(involvedIndexes, new IndexComparator());
                indexOnExactClass = true;
                // go through all possible index for given set of fields.
                for (final OIndex index : involvedIndexes) {
                    final long indexRebuildVersion = index.getRebuildVersion();
                    if (index.isRebuilding()) {
                        continue;
                    }
                    final OIndexDefinition indexDefinition = index.getDefinition();
                    if (searchResult.containsNullValues && indexDefinition.isNullValuesIgnored()) {
                        continue;
                    }
                    final OQueryOperator operator = searchResult.lastOperator;
                    // are equals.
                    if (!OIndexSearchResult.isIndexEqualityOperator(operator)) {
                        final String lastFiled = searchResult.lastField.getItemName(searchResult.lastField.getItemCount() - 1);
                        final String relatedIndexField = indexDefinition.getFields().get(searchResult.fieldValuePairs.size());
                        if (!lastFiled.equals(relatedIndexField)) {
                            continue;
                        }
                    }
                    final int searchResultFieldsCount = searchResult.fields().size();
                    final List<Object> keyParams = new ArrayList<Object>(searchResultFieldsCount);
                    // We get only subset contained in processed sub query.
                    for (final String fieldName : indexDefinition.getFields().subList(0, searchResultFieldsCount)) {
                        Object fieldValue = searchResult.fieldValuePairs.get(fieldName);
                        if (fieldValue instanceof OSQLQuery<?> || fieldValue instanceof OSQLFilterCondition) {
                            return false;
                        }
                        if (fieldValue != null) {
                            keyParams.add(fieldValue);
                        } else {
                            if (searchResult.lastValue instanceof OSQLQuery<?> || searchResult.lastValue instanceof OSQLFilterCondition) {
                                return false;
                            }
                            keyParams.add(searchResult.lastValue);
                        }
                    }
                    metricRecorder.recordInvolvedIndexesMetric(index);
                    OIndexCursor cursor;
                    indexIsUsedInOrderBy = orderByOptimizer.canBeUsedByOrderByAfterFilter(index, getEqualsClausesPrefix(searchResult), orderedFields) && !(index.getInternal() instanceof OChainedIndexProxy);
                    try {
                        boolean ascSortOrder = !indexIsUsedInOrderBy || orderedFields.get(0).getValue().equals(KEYWORD_ASC);
                        if (indexIsUsedInOrderBy) {
                            fullySortedByIndex = expandTarget == null && indexDefinition.getFields().size() >= orderedFields.size() && conditionHierarchy.size() == 1;
                        }
                        context.setVariable("$limit", limit);
                        cursor = operator.executeIndexQuery(context, index, keyParams, ascSortOrder);
                        if (!iSchemaClass.getName().equals(index.getDefinition().getClassName())) {
                            indexOnExactClass = false;
                        }
                    } catch (OIndexEngineException e) {
                        throw e;
                    } catch (Exception e) {
                        OLogManager.instance().error(this, "Error on using index %s in query '%s'. Probably you need to rebuild indexes. Now executing query using cluster scan", e, index.getName(), request != null && request.getText() != null ? request.getText() : "");
                        fullySortedByIndex = false;
                        cursors.clear();
                        return false;
                    }
                    if (cursor == null) {
                        continue;
                    }
                    if (index.getRebuildVersion() == indexRebuildVersion) {
                        cursors.add(OIndexChangesWrapper.wrap(index, cursor, indexRebuildVersion));
                        indexUseAttempts.add(new IndexUsageLog(index, keyParams, indexDefinition));
                        indexUsed = true;
                        break;
                    }
                }
                if (indexUsed) {
                    break;
                }
            }
            if (!indexUsed) {
                return tryOptimizeSort(iSchemaClass);
            }
        }
        if (cursors.size() == 0 || lastSearchResult == null) {
            return false;
        }
        if (cursors.size() == 1 && canOptimize(conditionHierarchy)) {
            filterOptimizer.optimize(compiledFilter, lastSearchResult);
        }
        uniqueResult = new ConcurrentHashMap<ORID, ORID>();
        if (cursors.size() == 1 && (compiledFilter == null || compiledFilter.getRootCondition() == null) && groupByFields == null && projections != null && projections.size() == 1) {
            // OPTIMIZATION: ONE INDEX USED WITH JUST ONE CONDITION: REMOVE THE FILTER
            final Entry<String, Object> entry = projections.entrySet().iterator().next();
            if (entry.getValue() instanceof OSQLFunctionRuntime) {
                final OSQLFunctionRuntime rf = (OSQLFunctionRuntime) entry.getValue();
                if (rf.function instanceof OSQLFunctionCount && rf.configuredParameters.length == 1 && "*".equals(rf.configuredParameters[0])) {
                    final boolean restrictedClasses = isUsingRestrictedClasses();
                    if (!restrictedClasses && indexOnExactClass) {
                        final OIndexCursor cursor = cursors.get(0);
                        long count = 0;
                        if (cursor instanceof OSizeable)
                            count = ((OSizeable) cursor).size();
                        else {
                            while (cursor.hasNext()) {
                                cursor.next();
                                count++;
                            }
                        }
                        final OProfiler profiler = Orient.instance().getProfiler();
                        if (profiler.isRecording()) {
                            profiler.updateCounter(profiler.getDatabaseMetric(database.getName(), "query.indexUsed"), "Used index in query", +1);
                        }
                        if (tempResult == null)
                            tempResult = new ArrayList<OIdentifiable>();
                        ((Collection<OIdentifiable>) tempResult).add(new ODocument().field(entry.getKey(), count));
                        return true;
                    }
                }
            }
        }
        for (OIndexCursor cursor : cursors) {
            if (!fetchValuesFromIndexCursor(cursor)) {
                break;
            }
        }
        uniqueResult.clear();
        uniqueResult = null;
        metricRecorder.recordOrderByOptimizationMetric(indexIsUsedInOrderBy, this.fullySortedByIndex);
        indexUseAttempts.clear();
        return true;
    } finally {
        for (IndexUsageLog wastedIndexUsage : indexUseAttempts) {
            revertProfiler(context, wastedIndexUsage.index, wastedIndexUsage.keyParams, wastedIndexUsage.indexDefinition);
        }
    }
}
Also used : OSQLFunctionRuntime(com.orientechnologies.orient.core.sql.functions.OSQLFunctionRuntime) OIdentifiable(com.orientechnologies.orient.core.db.record.OIdentifiable) ORID(com.orientechnologies.orient.core.id.ORID) ODocument(com.orientechnologies.orient.core.record.impl.ODocument) OProfiler(com.orientechnologies.common.profiler.OProfiler) OSQLFunctionCount(com.orientechnologies.orient.core.sql.functions.misc.OSQLFunctionCount) OException(com.orientechnologies.common.exception.OException) OQueryParsingException(com.orientechnologies.orient.core.exception.OQueryParsingException) OCommandExecutionException(com.orientechnologies.orient.core.exception.OCommandExecutionException) IOException(java.io.IOException) ExecutionException(java.util.concurrent.ExecutionException) OSizeable(com.orientechnologies.common.util.OSizeable) ODatabaseDocument(com.orientechnologies.orient.core.db.document.ODatabaseDocument)

Aggregations

OException (com.orientechnologies.common.exception.OException)1 OProfiler (com.orientechnologies.common.profiler.OProfiler)1 OSizeable (com.orientechnologies.common.util.OSizeable)1 ODatabaseDocument (com.orientechnologies.orient.core.db.document.ODatabaseDocument)1 OIdentifiable (com.orientechnologies.orient.core.db.record.OIdentifiable)1 OCommandExecutionException (com.orientechnologies.orient.core.exception.OCommandExecutionException)1 OQueryParsingException (com.orientechnologies.orient.core.exception.OQueryParsingException)1 ORID (com.orientechnologies.orient.core.id.ORID)1 ODocument (com.orientechnologies.orient.core.record.impl.ODocument)1 OSQLFunctionRuntime (com.orientechnologies.orient.core.sql.functions.OSQLFunctionRuntime)1 OSQLFunctionCount (com.orientechnologies.orient.core.sql.functions.misc.OSQLFunctionCount)1 IOException (java.io.IOException)1 ExecutionException (java.util.concurrent.ExecutionException)1