MongoDB
 sql >> Cơ Sở Dữ Liệu >  >> NoSQL >> MongoDB

Hiệu suất truy vấn MongoDB cho hơn 5 triệu bản ghi

Đây là mò kim đáy bể. Chúng tôi cần một số đầu ra của explain() cho những truy vấn không hoạt động tốt. Thật không may, ngay cả điều đó cũng sẽ chỉ khắc phục sự cố cho truy vấn cụ thể đó, vì vậy đây là chiến lược về cách tiếp cận điều này:

  1. Đảm bảo rằng đó không phải là do không đủ RAM và phân trang quá nhiều
  2. Bật trình biên dịch DB (sử dụng db.setProfilingLevel(1, timeout) trong đó timeout là ngưỡng cho số mili giây mà truy vấn hoặc lệnh thực hiện, mọi thứ chậm hơn sẽ được ghi lại)
  3. Kiểm tra các truy vấn chậm trong db.system.profile và chạy các truy vấn theo cách thủ công bằng cách sử dụng explain()
  4. Cố gắng xác định các hoạt động chậm trong explain() đầu ra, chẳng hạn như scanAndOrder hoặc nscanned lớn , v.v.
  5. Lý do về tính chọn lọc của truy vấn và liệu có thể cải thiện truy vấn bằng cách sử dụng chỉ mục hoàn toàn . Nếu không, hãy xem xét việc không cho phép cài đặt bộ lọc cho người dùng cuối hoặc cung cấp cho họ hộp thoại cảnh báo rằng hoạt động có thể chậm.

Một vấn đề quan trọng là bạn dường như đang cho phép người dùng của mình kết hợp các bộ lọc theo ý muốn. Nếu không có sự giao nhau giữa các chỉ mục, điều đó sẽ làm tăng đáng kể số lượng các chỉ mục cần thiết.

Ngoài ra, ném chỉ mục một cách mù quáng vào mọi truy vấn có thể là một chiến lược rất tồi. Điều quan trọng là phải cấu trúc các truy vấn và đảm bảo các trường được lập chỉ mục có đủ tính chọn lọc .

Giả sử bạn có một truy vấn cho tất cả người dùng có trạng thái status "hoạt động" và một số tiêu chí khác. Nhưng trong số 5 triệu người dùng, 3 triệu đang hoạt động và 2 triệu thì không, vì vậy hơn 5 triệu mục nhập chỉ có hai giá trị khác nhau. Một chỉ mục như vậy thường không hữu ích. Tốt hơn hết bạn nên tìm kiếm các tiêu chí khác trước, sau đó quét kết quả. Trung bình, khi trả lại 100 tài liệu, bạn sẽ phải quét 167 tài liệu, điều này sẽ không ảnh hưởng quá nhiều đến hiệu suất. Nhưng nó không đơn giản như vậy. Nếu tiêu chí chính là joined_at ngày của người dùng và khả năng người dùng ngừng sử dụng theo thời gian là cao, bạn có thể phải quét hàng nghìn trong số các tài liệu trước khi tìm thấy hàng trăm kết quả phù hợp.

Vì vậy, việc tối ưu hóa phụ thuộc rất nhiều vào dữ liệu (không chỉ cấu trúc của nó mà còn là bản thân dữ liệu ), các mối tương quan nội bộ của nó và các mẫu truy vấn của bạn .

Mọi thứ trở nên tồi tệ hơn khi dữ liệu quá lớn so với RAM, bởi vì khi đó, có một chỉ mục là rất tốt, nhưng việc quét (hoặc thậm chí chỉ đơn giản là trả lại) kết quả có thể yêu cầu tìm nạp nhiều dữ liệu từ đĩa một cách ngẫu nhiên, mất rất nhiều thời gian.

Cách tốt nhất để kiểm soát điều này là giới hạn số lượng các loại truy vấn khác nhau, không cho phép truy vấn thông tin có tính chọn lọc thấp và cố gắng ngăn truy cập ngẫu nhiên vào dữ liệu cũ.

Nếu vẫn thất bại và nếu bạn thực sự cần sự linh hoạt trong các bộ lọc, bạn nên xem xét một Cơ sở dữ liệu tìm kiếm riêng hỗ trợ các giao điểm chỉ mục, tìm nạp id mongo từ đó và sau đó nhận kết quả từ mongo bằng cách sử dụng $in . Nhưng điều đó đầy rẫy những nguy cơ của riêng nó.

- CHỈNH SỬA -

Giải thích bạn đã đăng là một ví dụ tuyệt vời về sự cố khi quét các trường có độ chọn lọc thấp. Rõ ràng, có rất nhiều tài liệu cho "[email protected]". Giờ đây, việc tìm kiếm những tài liệu đó và sắp xếp chúng giảm dần theo dấu thời gian khá nhanh chóng, bởi vì nó được hỗ trợ bởi các chỉ mục có tính chọn lọc cao. Rất tiếc, vì chỉ có hai loại thiết bị, mongo cần quét 30060 tài liệu để tìm loại đầu tiên phù hợp với 'di động'.

Tôi cho rằng đây là một loại theo dõi web nào đó và cách sử dụng của người dùng làm cho truy vấn chậm (nếu anh ta chuyển đổi thiết bị di động và web hàng ngày thì truy vấn sẽ nhanh).

Việc làm cho truy vấn cụ thể này nhanh hơn có thể được thực hiện bằng cách sử dụng chỉ mục kết hợp có chứa loại thiết bị, ví dụ:sử dụng

a) ensureIndex({'username': 1, 'userAgent.deviceType' : 1, 'timestamp' :-1})

hoặc

b) ensureIndex({'userAgent.deviceType' : 1, 'username' : 1, 'timestamp' :-1})

Rất tiếc, điều đó có nghĩa là các truy vấn như find({"username" : "foo"}).sort({"timestamp" : -1}); không thể sử dụng cùng một chỉ mục nữa, vì vậy, như đã mô tả, số lượng chỉ mục sẽ tăng lên rất nhanh.

Tôi e rằng không có giải pháp nào tốt cho việc này bằng cách sử dụng mongodb vào lúc này.



  1. Redis
  2.   
  3. MongoDB
  4.   
  5. Memcached
  6.   
  7. HBase
  8.   
  9. CouchDB
  1. Mẹo nâng cấp máy chủ Percona cho MongoDB

  2. Làm cách nào để đổi tên trường cho tất cả các tài liệu trong MongoDB?

  3. Cách VÀ và KHÔNG trong tìm kiếm văn bản MongoDB $

  4. Trợ giúp về biểu mẫu Rails + MongoMapper + EmbeddedDocument

  5. Làm cách nào để xóa hoàn toàn một trường khỏi tài liệu MongoDB?