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);
}
}
}
Aggregations