Mengoptimalkan kueri dengan filter rentang dan ketidaksetaraan di beberapa properti

Halaman ini memberikan contoh strategi pengindeksan yang harus digunakan untuk kueri dengan filter rentang & ketidaksetaraan di beberapa kolom untuk membuat pengalaman kueri yang efisien.

Baca konsep filter rentang dan ketidaksetaraan di beberapa properti sebelum mengoptimalkan kueri Anda.

Mengoptimalkan kueri dengan Penjelasan Kueri

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 menyimpan jumlah entity yang dipindai Firestore dalam mode Datastore.

Kueri sederhana

Dengan contoh sebelumnya kumpulan karyawan, kueri sederhana yang dijalankan 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 entitas. 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"
            }
        }
    }

Sesuai 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();

Jika Anda secara eksplisit menggunakan klausa orderBy() untuk menambahkan predikat pada urutan sebelumnya, Firestore dalam mode Datastore menggunakan indeks (salary, experience) untuk menjalankan kueri. Jadi, 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 Berikutnya