이 페이지에서는 효율적인 쿼리 환경을 만들기 위해 여러 필드에 범위 및 불일치 필터가 있는 쿼리에 사용할 수 있는 색인 생성 전략의 예시를 제공합니다.
쿼리를 최적화하기 전에 여러 속성의 범위 및 불일치 필터 개념을 읽어보세요.
Query Explain으로 쿼리 최적화
사용된 쿼리와 색인이 최적의 상태인지 확인하기 위해 Query Explain을 사용하여 쿼리를 만들고 실행 요약을 검토할 수 있습니다.
...
// Build the query
Query<Entity> query =
Query.newEntityQueryBuilder()
.setKind("employees")
.setFilter(
CompositeFilter.and(
PropertyFilter.gt("salary", 100000), PropertyFilter.gt("experience", 0)))
.setOrderBy(OrderBy("experience"), OrderBy("salary"))
.build();
// Set the explain options to get back *only* the plan summary
QueryResults<Entity> results = datastore.run(query, ExplainOptions.newBuilder().build());
// Get the explain metrics
Optional<ExplainMetrics> explainMetrics = results.getExplainMetrics();
if (!explainMetrics.isPresent()) {
throw new Exception("No explain metrics returned");
}
// Get the plan summary
PlanSummary planSummary = explainMetrics.get().getPlanSummary();
List<Map<String, Object>> indexesUsed = planSummary.getIndexesUsed();
System.out.println("----- Indexes Used -----");
indexesUsed.forEach(map -> map.forEach((s, o) -> System.out.println(s + ": " + o)));
// Get the execution stats
if (!explainMetrics.getExecutionStats().isPresent()) {
throw new Exception("No execution stats returned");
}
ExecutionStats queryStats = explainMetrics.getExecutionStats().get();
Map<String, Object> debugStats = queryStats.getDebugStats();
System.out.println("----- Debug Stats -----");
debugStats.forEach((s, o) -> System.out.println(s + ": " + o));
다음 예시는 올바른 색인 순서를 사용하여 Datastore 모드의 Firestore에서 스캔하는 항목 수를 줄이는 방법을 보여줍니다.
간단한 쿼리
직원 컬렉션의 이전 예시에서 (salary, experience)
색인을 사용해 실행되는 간단한 쿼리는 다음과 같습니다.
SELECT *
FROM /employees
WHERE salary > 100000 AND experience > 0
ORDER BY experience, salary;
Query<Entity> query =
Query.newEntityQueryBuilder()
.setKind("employees")
.setFilter(
CompositeFilter.and(
PropertyFilter.gt("salary", 100000), PropertyFilter.gt("experience", 0)))
.setOrderBy(OrderBy("experience"), OrderBy("salary"))
.build();
이 쿼리는 95,000개의 색인 항목을 스캔하여 5개 항목만을 반환합니다. 많은 수의 색인 항목을 읽었지만 쿼리 조건자를 충족하지 않아 필터링되었습니다.
// Output query planning info { "indexesUsed": [ { "query_scope": "Collection Group", "properties": "(experience ASC, salary ASC, __name__ ASC)" } ] }, // Output Query Execution Stats { "resultsReturned": "5", "executionDuration": "2.5s", "readOperations": "100", "debugStats": { "index_entries_scanned": "95000", "documents_scanned": "5", "billing_details": { "documents_billable": "5", "index_entries_billable": "95000", "small_ops": "0", "min_query_cost": "0" } } }
앞의 예시에 따라 salary
제약조건이 experience
제약조건보다 선택성이 높다고 추론할 수 있습니다.
SELECT *
FROM /employees
WHERE salary > 100000 AND experience > 0
ORDER BY salary, experience;
Query<Entity> query =
Query.newEntityQueryBuilder()
.setKind("employees")
.setFilter(
CompositeFilter.and(
PropertyFilter.gt("salary", 100000), PropertyFilter.gt("experience", 0)))
.setOrderBy(OrderBy("salary"), OrderBy("experience"))
.build();
orderBy()
절을 명시적으로 사용하여 앞의 순서로 조건자를 추가하면 Datastore 모드의 Firestore는 (salary, experience)
색인을 사용하여 쿼리를 실행합니다. 첫 번째 범위 필터의 선택이 이전 쿼리보다 우수하므로 쿼리가 더 빠르게 실행되며 비용 효율적입니다.
// Output query planning info { "indexesUsed": [ { "query_scope": "Collection Group", "properties": "(salary ASC, experience ASC, __name__ ASC)" } ], // Output Query Execution Stats "resultsReturned": "5", "executionDuration": "0.2s", "readOperations": "6", "debugStats": { "index_entries_scanned": "1000", "documents_scanned": "5", "billing_details": { "documents_billable": "5", "index_entries_billable": "1000", "small_ops": "0", "min_query_cost": "0" } } }
다음 단계
- Query Explain 자세히 알아보기