Tối ưu hoá truy vấn bằng bộ lọc phạm vi và bất đẳng thức trên nhiều trường

Trang này cung cấp các ví dụ về chiến lược lập chỉ mục nên được sử dụng cho các truy vấn có phạm vi & bộ lọc bất đẳng thức trên nhiều trường để tạo trải nghiệm truy vấn hiệu quả.

Đọc về các khái niệm có liên quan trước khi tối ưu hóa truy vấn.

Tối ưu hoá truy vấn bằng tính năng Giải thích truy vấn

Để xác định xem truy vấn và chỉ mục được sử dụng có tối ưu hay không, bạn có thể sử dụng Giải thích truy vấn để nhận tóm tắt kế hoạch truy vấn và thống kê thực thi của truy vấn:

Java

Query q = db.collection("employees").whereGreaterThan("salary",
100000).whereGreaterThan("experience", 0);

ExplainResults<QuerySnapshot> explainResults = q.explain(ExplainOptions.builder().analyze(true).build()).get();
ExplainMetrics metrics = explainResults.getMetrics();

PlanSummary planSummary = metrics.getPlanSummary();
ExecutionStats executionStats = metrics.getExecutionStats();

System.out.println(planSummary.getIndexesUsed());
System.out.println(stats.getResultsReturned());
System.out.println(stats.getExecutionDuration());
System.out.println(stats.getReadOperations());
System.out.println(stats.getDebugStats());

Node.js

let q = db.collection("employees")
      .where("salary", ">", 100000)
      .where("experience", ">",0);

let options = { analyze : 'true' };
let explainResults = await q.explain(options);

let planSummary = explainResults.metrics.planSummary;
let stats = explainResults.metrics.executionStats;

console.log(planSummary);
console.log(stats);

Ví dụ sau đây cho thấy việc sử dụng đúng thứ tự chỉ mục sẽ giúp giảm số lượng mục nhập chỉ mục mà Cloud Firestore quét.

Truy vấn đơn giản

Với ví dụ trước đó về tập hợp nhân viên, truy vấn đơn giản chạy với chỉ mục (experience ASC, salary ASC) như sau:

Java

db.collection("employees")
  .whereGreaterThan("salary", 100000)
  .whereGreaterThan("experience", 0)
  .orderBy("experience")
  .orderBy("salary");

Truy vấn quét 95000 mục nhập chỉ mục để trả về 5 tài liệu. Do thuộc tính truy vấn không được đáp ứng, một số lượng lớn các mục nhập chỉ mục được đọc nhưng bị lọc ra.

// Output query planning info
{
    "indexesUsed": [
        {
            "properties": "(experience ASC, salary ASC, __name__ ASC)",
            "query_scope": "Collection"
        }
    ],

    // 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"
        }
    }
}

Từ kiến thức chuyên môn về miền, chúng tôi có thể suy ra rằng hầu hết nhân viên đều có ít nhất một chút kinh nghiệm nhưng rất ít nhân viên có mức lương cao hơn 100.000. Dựa trên thông tin chi tiết này, chúng ta có thể kết luận rằng quy tắc ràng buộc salary có tính lựa chọn cao hơn so với quy tắc ràng buộc experience. Để tác động đến chỉ mục mà Cloud Firestore sử dụng để thực thi truy vấn, hãy chỉ định mệnh đề orderBy sắp xếp quy tắc ràng buộc salary trước quy tắc ràng buộc experience.

Java

db.collection("employees")
  .whereGreaterThan("salary", 100000)
  .whereGreaterThan("experience", 0)
  .orderBy("salary")
  .orderBy("experience");

Khi bạn rõ ràng sử dụng mệnh đề orderBy() để thêm các thuộc tính, Cloud Firestore sẽ sử dụng chỉ mục (salary ASC, experience ASC) để chạy truy vấn. Như vậy, vì độ chọn lọc của bộ lọc dải ô đầu tiên trong truy vấn này cao hơn so với thì truy vấn trước đó sẽ chạy nhanh hơn và tiết kiệm chi phí hơn.

// Output query planning info
{
    "indexesUsed": [
        {
            "properties": "(salary ASC, experience ASC, __name__ ASC)",
            "query_scope": "Collection"
        }
    ],

    // 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"
        }
    }
}

Bước tiếp theo