Các chỉ mục mongodb có được lưu trữ trong bộ nhớ không?

Bài đăng trên blog này là một phần của Lịch Mùa Vọng Mixmax 2017. Bài viết trước ngày 9 tháng 12 về Giới thiệu chuỗi tìm kiếm. trình phân tích chuỗi tìm kiếm nâng cao

Truy vấn các bộ sưu tập lớn một cách hiệu quả

Hãy tưởng tượng bạn muốn tìm hiểu thêm về hiệu suất của cơ sở dữ liệu và bạn có trong tay một cuốn sách rất lớn về cơ sở dữ liệu nói chung. Làm thế nào bạn có thể tìm kiếm chủ đề bạn quan tâm?

Thường xuyên hơn không, câu trả lời là. đi đến mục lục (thường nằm ở cuối sách), tra cứu chủ đề (thường trong danh sách theo thứ tự bảng chữ cái) và mục lục sẽ cho bạn biết trang mà chủ đề đó được thảo luận

Nếu cuốn sách không có mục lục, có lẽ bạn cần phải xem qua từng trang và cố gắng tìm thông tin liên quan về hiệu suất - đó sẽ là một nỗ lực lâu dài và tẻ nhạt

Tương tự, khi bạn yêu cầu một số tài liệu trong cơ sở dữ liệu, cơ sở dữ liệu sẽ cố gắng sử dụng một chỉ mục để nhanh chóng tìm thấy kết quả cho bạn. Nếu không có chỉ mục để sử dụng làm tài liệu tham khảo, thì nó phải kiểm tra từng tài liệu, giống như cách bạn sẽ làm nếu sách của bạn không có chỉ mục. Cơ sở dữ liệu có thể xử lý được nếu không có nhiều tài liệu để tìm kiếm, nhưng khi cơ sở dữ liệu của bạn có gần 1 tỷ tài liệu và đang được truy vấn hàng nghìn lần trong một giây. sau đó nó trở thành một vấn đề

Chỉ mục là cấu trúc dữ liệu cho phép cơ sở dữ liệu nhanh chóng tìm thấy tài liệu trong bộ sưu tập. Trong Mongo, bạn xác định chỉ mục bằng lệnh như thế này

db.events.ensureIndex({
  action: 1
}, {
  background: true,
  name: 'events_index_by_action'
});

Phần trên yêu cầu cơ sở dữ liệu tạo chỉ mục trên các giá trị từ thuộc tính

db.events.find({
  action: 'send email'
});
6 của bộ sưu tập
db.events.find({
  action: 'send email'
});
0 (ngoài ra, nó yêu cầu cơ sở dữ liệu tạo chỉ mục trong nền). Vì việc xây dựng chỉ mục là một thao tác chặn nên đối với các bộ sưu tập rất lớn, có thể mất nhiều giờ để hoàn thành việc xây dựng chỉ mục, khiến cơ sở dữ liệu ngừng trả lời bất kỳ truy vấn nào khác

Với chỉ số trên cơ sở dữ liệu sẽ có thể truy xuất kết quả một cách hiệu quả khi truy vấn bằng

db.events.find({
  action: 'send email'
});
6. Ví dụ, truy vấn này

db.events.find({
  action: 'send email'
});

sẽ rất nhanh, bởi vì cơ sở dữ liệu có thể nhanh chóng lấy tất cả các tài liệu phù hợp với hành động

db.events.find({
  action: 'send email'
});
2 và trả lại cho bạn

Bây giờ, nếu bạn muốn xem

db.events.find({
  action: 'send email'
});
2 sự kiện kể từ một tháng trước

db.events.find({
  action: 'send email',
  date: { $gt: moment().subtract(1, 'month').toDate() }
});

Cơ sở dữ liệu sẽ có thể truy xuất tất cả các sự kiện

db.events.find({
  action: 'send email'
});
2 rất nhanh bằng cách sử dụng chỉ mục. Tuy nhiên, nếu
db.events.find({
  action: 'send email'
});
2 là một sự kiện rất phổ biến, thì truy vấn sẽ rất chậm. Điều này là do bạn không thể lọc thêm theo
db.events.find({
  action: 'send email'
});
6 bằng cách sử dụng chỉ mục đó, vì vậy cơ sở dữ liệu sẽ phải kiểm tra từng sự kiện trong số hàng triệu sự kiện của
db.events.find({
  action: 'send email'
});
2

Xác định các chỉ số hiệu quả

Để khắc phục trường hợp khi bạn muốn lọc các sự kiện của chúng tôi theo phạm vi ngày, bạn có thể tiếp tục xây dựng dựa trên chỉ mục đã xác định trước đó và xác định nó như sau

db.events.find({
  action: 'send email'
});
0

Chỉ mục tổng hợp ở trên sẽ cải thiện hiệu suất của truy vấn cũng lọc theo

db.events.find({
  action: 'send email'
});
6. Tuy nhiên, mặc dù nhìn thoáng qua nó có vẻ chính xác, nhưng nếu bạn hình dung cơ sở dữ liệu sẽ tìm kiếm tài liệu bằng cách sử dụng chỉ mục như thế nào, bạn có thể đoán tại sao nó không thực sự là chỉ mục tốt nhất cho truy vấn đó

Hãy tưởng tượng rằng bạn có một cuốn sách về các sự kiện. Trong mục lục của cuốn sách, bạn có thể thấy 20 loại sự kiện khác nhau và đối với mỗi sự kiện, bạn sẽ thấy một danh sách rất dài các trang có thể tìm thấy một sự kiện nhất định trong một ngày nhất định. Giả sử rằng các sự kiện của bạn được phân bổ ít nhiều đồng đều theo hành động và quy mô bộ sưu tập của bạn là 1 tỷ sự kiện, nếu bạn tìm kiếm theo sự kiện trước, thì bạn sẽ giảm khoảng 1/20 khu vực tìm kiếm. Điều này có nghĩa là, trong số 1 tỷ tài liệu ban đầu, giờ đây bạn phải quét 50 triệu tài liệu

Điều gì sẽ xảy ra nếu chỉ mục hiển thị cho bạn ngày đầu tiên thay vì hành động trước? . Giả sử bạn có dữ liệu sự kiện lịch sử trong 4 năm và đang truy vấn các sự kiện trong một ngày, việc lập chỉ mục theo ngày trước tiên sẽ giảm khu vực tìm kiếm của bạn xuống 1/1460 trong bước đầu tiên. Bây giờ bạn chỉ cần quét ~1. 35 triệu tài liệu - ít hơn khoảng 37 lần so với nếu bạn quét theo loại sự kiện trước. Chỉ số sẽ trông như thế này

db.events.find({
  action: 'send email'
});
2

Khi tạo một chỉ mục phức hợp như chỉ mục trong ví dụ này, hãy tự hỏi mình câu hỏi này. "Thuộc tính nào trong truy vấn tìm kiếm của tôi là thuộc tính 'duy nhất' nhất?" . Thuộc tính 'tính duy nhất' này của thuộc tính tài liệu được gọi là 'cardinality'. Các thuộc tính đầu tiên của bạn trong chỉ mục tổng hợp có số lượng thẻ càng cao thì nó sẽ hoạt động càng tốt, bởi vì các trường có số lượng thẻ cao hơn thực hiện tốt hơn việc giảm khu vực tìm kiếm của truy vấn

Đảm bảo rằng các chỉ mục được sử dụng hiệu quả

Giờ đây, bộ sưu tập của bạn có các chỉ mục được xác định độc đáo với các trường có số lượng thẻ cao ở trên cùng, đảm bảo rằng không gian tìm kiếm của bạn được giảm đáng kể ngay từ đầu. Tuyệt vời. Bây giờ làm thế nào bạn có thể đảm bảo rằng cơ sở dữ liệu của bạn sử dụng chỉ mục một cách hiệu quả nhất có thể?

Để các chỉ mục được sử dụng hiệu quả, bạn muốn chúng vừa với RAM có sẵn trong máy chủ cơ sở dữ liệu. RAM trong Mongo chủ yếu được sử dụng để giữ các chỉ mục và dữ liệu được yêu cầu thường xuyên nhất - đây được gọi là bộ làm việc. Trên công cụ lưu trữ WiredTiger, dung lượng RAM mặc định được sử dụng cho bộ làm việc là

db.events.find({
  action: 'send email',
  date: { $gt: moment().subtract(1, 'month').toDate() }
});
1 hoặc
db.events.find({
  action: 'send email',
  date: { $gt: moment().subtract(1, 'month').toDate() }
});
2, tùy theo giá trị nào cao nhất. Giả sử bạn có một máy chủ với 32gb RAM, điều này có nghĩa là có 15gb cho bộ nhớ cache. Mongo sử dụng không gian này để xử lý các chỉ mục và dữ liệu được truy xuất phổ biến nhất (nó có thể tải một tập hợp con của một chỉ mục). Mongo cũng sử dụng bộ nhớ cho các tác vụ khác, như quản lý kết nối và xử lý tập hợp, chưa kể các quy trình khác đang chạy trong máy bên cạnh Mongo

Không có gì lạ khi để hỗ trợ nhiều cách khác nhau để truy vấn một bộ sưu tập, bạn sẽ cần xác định nhiều chỉ mục. Việc cải thiện các truy vấn tra cứu bằng cách thêm các chỉ mục mà không cần cân nhắc nhiều là rất hấp dẫn, nhưng đây cũng là một cách dễ dàng để làm phình to cơ sở dữ liệu với nhiều chỉ mục. Bạn có thể kiểm tra kích thước chỉ mục tổng thể của cơ sở dữ liệu của mình như vậy

db.events.find({
  action: 'send email'
});
6

Đây là kích thước của tất cả các chỉ mục trong cơ sở dữ liệu theo byte. Trong ví dụ này là 65gb. Đây không phải là kích thước lý tưởng cho máy chủ có 32gb như ví dụ trên. Vì các chỉ mục này không thể vừa với bộ nhớ, nên bạn sẽ thực hiện các thao tác đọc từ đĩa và sẽ bị hạn chế nghiêm trọng bởi thông lượng I/O của đĩa

Không dễ để biết cơ sở dữ liệu của bạn cần bao nhiêu bộ nhớ. Một số câu hỏi bạn có thể muốn xem xét

  1. Dữ liệu của bạn lớn đến mức nào?
  2. Dữ liệu được yêu cầu thường xuyên như thế nào (để xác định kích thước tập hợp làm việc gần đúng)?
  3. Làm thế nào lớn là chỉ số của bạn?
  4. Mức tăng trưởng dữ liệu dự kiến ​​của bạn trong ngắn hạn/trung hạn là bao nhiêu?

Các chiến lược để giữ kích thước chỉ mục nhỏ

Dưới đây là một số cách để giữ cho kích thước chỉ mục nhỏ được sắp xếp theo độ khó tăng dần

Xóa các chỉ mục không sử dụng

Bạn có thể kiểm tra các chỉ mục của một bộ sưu tập nhất định và cách sử dụng chúng như vậy

db.events.find({
  action: 'send email'
});
7

Trong ví dụ trên, có hai chỉ số. Dưới

db.events.find({
  action: 'send email',
  date: { $gt: moment().subtract(1, 'month').toDate() }
});
3, bạn có thể thấy rằng chỉ mục đầu tiên đã được sử dụng nhiều lần. Trong khi đó, chỉ số thứ hai hoàn toàn không được sử dụng. nó là một ứng cử viên cho việc loại bỏ. Giả sử có một lượt truy cập thứ ba với rất ít lượt truy cập, chẳng hạn khoảng 100. Chỉ mục đó có thể là một ứng cử viên để loại bỏ. Tuy nhiên, điều quan trọng là phải hiểu truy vấn nào đã sử dụng chỉ mục để hiểu tác động của việc xóa chỉ mục đã nói ở cấp ứng dụng

Lưu ý rằng số hoạt động có thể là lừa đảo, vì số lần sử dụng được tính kể từ thời điểm quá trình máy chủ Mongo bắt đầu, trong trường hợp này là kể từ ngày 2 tháng 11

Loại bỏ các chỉ mục dư thừa

Tương tự như trên, bạn có thể kiểm tra định nghĩa của các chỉ mục của mình. Ví dụ trong đầu ra này

db.events.find({
  action: 'send email'
});
9

Bạn có thể thấy rằng cả hai chỉ mục đều được sử dụng, vì vậy thoạt nhìn cả hai đều cần thiết. Tuy nhiên, chỉ mục thứ hai làm cho chỉ mục thứ nhất trở nên dư thừa, vì chỉ truy vấn trên

db.events.find({
  action: 'send email'
});
6 sẽ có thể sử dụng chỉ mục thứ hai mà không gặp vấn đề gì. Nói chung, đối với các chỉ mục phức hợp, một truy vấn sẽ có thể sử dụng nó miễn là các trường trong truy vấn xuất hiện theo thứ tự. Chẳng hạn, một truy vấn chỉ có
db.events.find({
  action: 'send email'
});
6 sẽ không thể sử dụng chỉ mục thứ hai ở trên, bởi vì
db.events.find({
  action: 'send email'
});
6 là thuộc tính được lập chỉ mục thứ hai trong chỉ mục phức hợp

Sử dụng các chỉ mục thưa thớt

Kích thước chỉ mục có thể được giảm đáng kể bằng cách làm cho các chỉ mục trở nên thưa thớt. Khi xác định một chỉ mục, bạn có thể áp dụng một ràng buộc cho chỉ mục biết tài liệu nào cần lập chỉ mục. Ràng buộc này được đặt tên là

db.events.find({
  action: 'send email',
  date: { $gt: moment().subtract(1, 'month').toDate() }
});
7. Ví dụ: trong trường hợp truy vấn các sự kiện theo loại và ngày, yêu cầu của sản phẩm là hỗ trợ tìm kiếm các sự kiện được kích hoạt bởi tương tác thủ công của người dùng. Vì bạn không quan tâm đến các sự kiện được kích hoạt thông qua tự động hóa hoặc sử dụng API, nên bạn có thể xác định một chỉ mục như vậy

db.events.find({
  action: 'send email'
});
3

Giả sử rằng 60% sự kiện được kích hoạt bởi tương tác trực tiếp của người dùng, điều này có nghĩa là chỉ mục chỉ lập chỉ mục cho 60% tài liệu trong bộ sưu tập, giúp tiết kiệm bộ nhớ

Giảm kích thước bộ sưu tập

Càng ít dữ liệu trong cơ sở dữ liệu, các chỉ mục sẽ càng nhỏ và cần ít bộ nhớ hơn để giữ nó trong RAM và đảm bảo phản hồi nhanh. Bạn có thể giảm kích thước bộ sưu tập bằng cách di chuyển dữ liệu cũ sang bộ lưu trữ "lạnh". Trong trường hợp của bộ sưu tập

db.events.find({
  action: 'send email'
});
0, dữ liệu có giá trị trong bốn năm và có khả năng không có nhiều nhu cầu truy xuất dữ liệu cũ. Bạn có thể xóa dữ liệu đó khỏi cơ sở dữ liệu đến một nơi khác để lưu trữ, miễn là bạn cung cấp phương tiện để truy xuất dữ liệu đã nói (với sự hiểu biết rằng đó là một quá trình chậm hơn

Giữ các chỉ mục đơn giản

Các chỉ mục tổng hợp rất mạnh mẽ, vì chúng sẽ hỗ trợ tạo các bộ lọc chi tiết hơn. Tuy nhiên, các chỉ số phức tạp hơn để duy trì và lớn hơn về bản chất. Cố gắng giảm thiểu số lượng trường trong một chỉ mục phức hợp để giữ cho chúng nhỏ

Điều này có lẽ nói dễ hơn làm, nhưng điều này đòi hỏi nhiều thời gian dành cho việc thiết kế lược đồ cơ sở dữ liệu. Chỉ vì Mongo được coi là "không có lược đồ" không nhất thiết có nghĩa là bạn chỉ nên bắt đầu viết mã, bỏ qua thiết kế của lược đồ và tìm ra nó trên đường đi. Để xác định một lược đồ tốt, điều quan trọng là phải hiểu rõ về sản phẩm, xem xét các yêu cầu hiện tại cũng như dự đoán các yêu cầu trong tương lai. Thiết kế một lược đồ tốt đòi hỏi một số khả năng đọc tương lai

sharding

Chia sẻ cơ sở dữ liệu là một tùy chọn khác. Điều này về cơ bản có nghĩa là dữ liệu được phân vùng theo một số tiêu chí (khóa phân đoạn) và được lưu trên nhiều cụm. Tùy chọn này thậm chí có thể phức tạp hơn tùy chọn trước đó - nó đòi hỏi bạn phải hiểu rõ về lược đồ và hơn nữa, bạn phải có kế hoạch hỗ trợ sharding ngay từ khi lược đồ được thiết kế

Để thiết lập phân đoạn có hiệu quả, khóa phân đoạn phải đảm bảo phân phối dữ liệu đồng đều trên các phân đoạn. Ví dụ: hãy tưởng tượng bạn có 5 phân đoạn lưu trữ dữ liệu cho 5 loại hành động khác nhau. Nếu 70% sự kiện là

db.events.find({
  action: 'send email',
  date: { $gt: moment().subtract(1, 'month').toDate() }
});
9, thì một phân đoạn sẽ nhận được 70% dữ liệu của bạn, trong khi phần còn lại sẽ nhận được 30% trên 4 phân đoạn đó

kết luận

Có thể ngạc nhiên về tần suất bạn có thể tìm thấy kết quả treo thấp khi cải thiện hiệu suất trong cơ sở dữ liệu. Chỉ cần loại bỏ các chỉ mục không sử dụng và dư thừa có thể là một sự gia tăng lớn về hiệu suất. Hơn nữa, việc dành thời gian thiết kế một lược đồ bằng chứng chắc chắn, trong tương lai có thể bổ ích về lâu dài, cho phép bạn chạy cơ sở dữ liệu của mình trong các máy chủ nhỏ hơn và giúp triển khai các cải tiến hiệu suất khác, chẳng hạn như sharding

Các chỉ mục có được lưu trữ trong bộ nhớ không?

Một chỉ mục thường được duy trì dưới dạng Cây B+ trên đĩa & trong bộ nhớ và mọi chỉ mục được lưu trữ trong các khối trên đĩa. Các khối này được gọi là khối chỉ mục. Các mục trong khối chỉ mục luôn được sắp xếp theo khóa chỉ mục/tìm kiếm.

MongoDB có lưu trữ dữ liệu trong bộ nhớ không?

MongoDB không phải là cơ sở dữ liệu trong bộ nhớ . Mặc dù nó có thể được cấu hình để chạy theo cách đó. Nhưng nó sử dụng bộ đệm một cách tự do, nghĩa là các bản ghi dữ liệu được lưu giữ trong bộ nhớ để truy xuất nhanh, trái ngược với trên đĩa.

Các chỉ mục MongoDB có được nén không?

Đối với các chỉ mục MongoDB sử dụng tính năng nén tiền tố chỉ mục để lưu trữ các chỉ mục trong bộ nhớ . "Nén tiền tố khóa" là một cách nén dữ liệu dành riêng cho miền và đề cập đến định dạng lưu trữ khóa trong WiredTiger. Điều này gần như làm giảm kích thước chỉ mục tối đa lên tới 97% khi so sánh với các chỉ mục MMAP trước đó.

Chỉ mục ở đâu trong bộ sưu tập MongoDB?

Tìm chỉ mục . Điều này sẽ trả về tất cả các chỉ mục trong một bộ sưu tập cụ thể. Kết quả. Đầu ra chứa chỉ mục _id mặc định và chỉ mục tên sinh viên do người dùng tạo chỉ mục. using the getIndexes method. This will return all the indexes in a specific collection. Result: The output contains the default _id index and the user-created index student name index.