Halaman ini memberikan contoh strategi pengindeksan yang dapat Anda gunakan untuk kueri dengan filter rentang dan ketidaksetaraan di beberapa kolom untuk menciptakan pengalaman kueri yang efisien.
Sebelum mengoptimalkan kueri, baca konsep filter rentang dan ketidaksetaraan di beberapa properti .
Mengoptimalkan kueri dengan Query Explain
Untuk menentukan apakah kueri dan indeks yang digunakan sudah optimal, Anda dapat membuat kueri menggunakan Query Explain dan meninjau ringkasan eksekusi.
Java
...
// 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
ExplainResults<Entity> explainResults = 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));
Contoh berikut menunjukkan bagaimana penggunaan pengurutan indeks yang benar menghemat jumlah entity yang dipindai Firestore dalam mode Datastore.
Kueri sederhana
Dengan contoh sebelumnya dari kumpulan karyawan, kueri sederhana
yang berjalan dengan indeks (salary, experience)
adalah sebagai berikut:
GQL
SELECT *
FROM /employees
WHERE salary > 100000 AND experience > 0
ORDER BY experience, salary;
Java
Query<Entity> query =
Query.newEntityQueryBuilder()
.setKind("employees")
.setFilter(
CompositeFilter.and(
PropertyFilter.gt("salary", 100000), PropertyFilter.gt("experience", 0)))
.setOrderBy(OrderBy("experience"), OrderBy("salary"))
.build();
Kueri memindai 95.000 entri indeks hanya untuk menampilkan 5 entity. Sejumlah besar entri indeks dibaca, tetapi difilter karena tidak memenuhi predikat kueri.
// 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" } } }
Seperti contoh sebelumnya, kita dapat menyimpulkan bahwa batasan salary
lebih
selektif daripada batasan experience
.
GQL
SELECT *
FROM /employees
WHERE salary > 100000 AND experience > 0
ORDER BY salary, experience;
Java
Query<Entity> query =
Query.newEntityQueryBuilder()
.setKind("employees")
.setFilter(
CompositeFilter.and(
PropertyFilter.gt("salary", 100000), PropertyFilter.gt("experience", 0)))
.setOrderBy(OrderBy("salary"), OrderBy("experience"))
.build();
Saat Anda secara eksplisit menggunakan klausa orderBy()
untuk menambahkan predikat dalam urutan sebelumnya, Firestore dalam mode Datastore akan menggunakan indeks (salary, experience)
untuk menjalankan kueri. Karena pemilihan filter rentang pertama lebih baik daripada kueri sebelumnya, kueri berjalan lebih cepat dan hemat biaya.
// 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" } } }
Langkah selanjutnya
- Pelajari Query Explain.