Computer >> Máy Tính >  >> Lập trình >> Cơ sở dữ liệu

Tìm các chỉ mục không sử dụng trong MongoDB

Tìm các chỉ mục không sử dụng trong MongoDB

Bắt đầu từ phiên bản 3.2, MongoDB theo dõi số liệu thống kê sử dụng cho mọi chỉ mục. Để truy cập các số liệu thống kê này, MongoDB cung cấp giai đoạn đường ống tổng hợp $ indexStats. Dưới đây là sáu cân nhắc khi tìm các chỉ mục không sử dụng trong MongoDB.

Ví dụ:lệnh sau sẽ cung cấp thống kê chỉ mục cho tập hợp “test.foo”:

 db.foo.aggregate ([{$ indexStats:{}}]) 

https://bit.ly/2seXnzo

Chúng tôi sẽ không mô tả đầu ra $ indexStats vì có rất nhiều tài liệu và nhiều bài báo hay về chủ đề này. Thay vào đó, chúng tôi sẽ cung cấp sáu cân nhắc về các lĩnh vực khác nhau khi sử dụng toán tử $ indexStats.

Cân nhắc 1:Thống kê được đặt lại sau mỗi lần khởi động lại dịch vụ

Luôn chú ý đến trường “accesses.since” khi sử dụng toán tử $ indexStats. Một số mẫu truy vấn có thể không thường xuyên, chẳng hạn như quy trình hàng loạt cuối ngày hoặc báo cáo hàng tuần, vì vậy hãy đảm bảo thời lượng thống kê bạn sẽ đánh giá bao gồm nhu cầu của bạn. Tập lệnh sau cho phép bạn đặt ngưỡng (tính bằng giờ) và sẽ in cảnh báo nếu chỉ mục không sử dụng không tuân thủ.

 ngưỡng_giờ =24; db.foo.aggregate ([{$ indexStats:{}}]) .forEach (function (f) {if (f.accesses.ops ==0) {if (ISODate () - f.accesses.since  

Ngưỡng phù hợp với bạn là gì? Không có câu trả lời đơn giản. Không phải tất cả các mẫu câu lệnh đều được thực thi với cùng một tần suất, vì vậy ngưỡng phù hợp khác nhau giữa các ứng dụng và cũng có thể khác nhau trên mỗi tập hợp trong cùng một cơ sở dữ liệu.

Cân nhắc 2:Số lần đọc phụ

Theo mặc định, $ indexStats đọc từ Chính. Nếu ứng dụng của bạn chỉ đọc từ Bản thứ hai, việc chạy $ indexStats so với Bản chính sẽ dẫn đến kết luận sai. Để đọc kết quả từ Phân đoạn thứ hai, bạn có thể sử dụng tập lệnh từ lần xem xét đầu tiên ở trên, nhưng thực thi db.getMongo (). SetReadPref (‘thứ cấp’) trước khi chạy nó, điều này buộc phải đọc lệnh từ Biệt thư.

Câu hỏi bây giờ là "điều gì sẽ xảy ra nếu một bộ sưu tập nhận được cả lượt đọc Tiểu học và Trung học?" Sử dụng tập lệnh sau, bạn có thể điền vào mảng idx các chỉ mục không được sử dụng trên cả Chính và Phụ:

 idx =[]; db.foo.getIndexes (). forEach (function (f) {idx.push (f.name)}) db.getMongo (). setReadPref ('primary'); db.foo. tổng hợp ([{$ indexStats:{}}]) .forEach (function (f) {if (f.accesses.ops> 0) {var index =idx.indexOf (f.name); if (index> -1) {idx.splice (index, 1);};}}) db.getMongo (). setReadPref ('Secondary'); db.foo.aggregate ([{$ indexStats:{}}]) .forEach (function (f ) {if (f.accesses.ops> 0) {var index =idx.indexOf (f.name); if (index> -1) {idx.splice (index, 1);};}}) 

Nội dung của mảng idx sẽ chứa các chỉ mục không được sử dụng trên cả Chính và Phụ. Còn về cửa sổ tuân thủ (ngưỡng_giờ) thì sao? Sửa đổi một chút tập lệnh từ xem xét 1 (tiểu mục trước) sẽ cho phép chúng tôi áp dụng tuân thủ thời gian. Chỉ cần thay thế phần tổng hợp bằng phần được cung cấp bên dưới và thực thi tập lệnh chống lại Phần phụ chính và Phụ bằng cách sử dụng setReadPref:

 db.foo.aggregate ([{$ indexStats:{}}, {$ match:{"name":{$ in:idx}}}]). 

Nếu Bộ phận chính và Bộ phận thứ hai trả về các kết quả tuân thủ khác nhau, thì cách tốt nhất là đợi cả hai cấp tuân thủ.

Việc sử dụng Tùy chọn đọc thứ cấp có thể dẫn đến “kết quả không chính xác” trong trường hợp Trang phụ được khởi động lại gần đây và tập lệnh chọn Phụ đó để lấy số liệu thống kê. Đối với trường hợp này, một cách tốt là kiểm tra db.serverStatus (). Thời gian hoạt động và chọn Phụ có thời gian hoạt động cao hơn. Phương pháp thời gian hoạt động yêu cầu một cách tiếp cận khác trên tập lệnh sẽ được triển khai trong bản sửa đổi trong tương lai của bài đăng blog này.

Cân nhắc 3:Thẻ đặt bản sao

Thẻ tập hợp bản sao có thể áp dụng trong nhiều trường hợp sử dụng nhưng chủ yếu được sử dụng cho địa phương đọc trong kịch bản sao chép địa lý và để nhắm mục tiêu khối lượng công việc cụ thể đến các nút chuyên dụng (ví dụ:hoạt động phân tích nặng). Khi nói đến nhắm mục tiêu theo khối lượng công việc, các nút được gắn thẻ phải được kiểm tra riêng biệt vì chúng có thể sử dụng một chỉ mục hoặc các chỉ mục mà các nút khác không sử dụng. Điều này cũng có thể là trường hợp trong sao chép địa lý, mặc dù nó hiếm hơn. Tập lệnh từ xem xét 1 có thể được sử dụng để kiểm tra thành viên được gắn thẻ, với việc bổ sung readPreference ở đầu tập lệnh. Dưới đây là một ví dụ để đặt tùy chọn đọc thành Tùy chọn phụ được đánh dấu để phân tích:

 db.getMongo (). setReadPref ('phụ', [{"khối lượng công việc":"phân tích"}]). 

Cách tiếp cận trong tương lai, được mô tả trong đoạn cuối cùng của phần thứ hai ở trên, có thể được mở rộng để kiểm tra cả những Thứ hai được gắn thẻ.

Cân nhắc 4:Chỉ mục TTL

Các chỉ mục TTL phục vụ các hoạt động nhưng công dụng chính của chúng là để lược bớt dữ liệu. Rất có thể $ indexStats sẽ báo cáo các chỉ mục này là không được sử dụng vì trình theo dõi TTL không được tính là hoạt động lập chỉ mục. Bạn chắc chắn không muốn giảm chỉ mục TTL dựa trên kết quả báo cáo $ indexStats, vì vậy các tập lệnh phải loại trừ loại chỉ mục này.

Một sửa đổi nhỏ trên tập lệnh mảng idx điền từ phần thứ hai sẽ thực hiện công việc. Thay thế dòng thứ hai bằng dòng sau và mảng idx sẽ không chứa bất kỳ (các) chỉ mục TTL nào.

 db.foo.getIndexes (). forEach (function (f) {if (f.expireAfterSeconds ==undefined) {idx.push (f.name)}}) 

Thảo luận thêm về các chỉ mục bị loại trừ một bước nữa, chúng tôi có thể khẳng định rằng _id cũng thuộc loại này. Rõ ràng, bạn không thể giảm chỉ mục _id ngay cả khi nó không được sử dụng. Một bộ sưu tập không bao giờ chạm vào chỉ mục _id có thể cần được thiết kế lại.

Cân nhắc 5:Các cụm bị chia nhỏ

Khi nói đến các cụm phân đoạn, có hai mục cần xem xét trước khi đánh giá đầu ra của $ indexStats. Đầu tiên, khi sử dụng $ indexStats với một tập hợp phân đoạn, có thể chỉ mục khóa phân đoạn được phân loại là không sử dụng. Ví dụ:một bộ sưu tập nhiều chữ viết được chia nhỏ trên {_id:”hashed”} (để phân phối đều các lần ghi) nhưng không có bất kỳ thao tác đọc / cập nhật / xóa nào có thể sử dụng chỉ mục _id. Trong trường hợp này, {_id:”hashed”} báo cáo như không sử dụng. Bạn không nên giảm chỉ mục vì nó sẽ phá vỡ cụm phân đoạn của bạn. Nếu bạn muốn loại trừ khóa phân đoạn cho bộ sưu tập ‘stats.foo’, tập lệnh sau có thể được đính kèm với phương thức được mô tả trong hai phương thức (lần đọc phụ) và khóa phân đoạn sẽ bị loại trừ khỏi mảng idx.

 shardkey =db.getSiblingDB ('config'). collection.findOne ({_ id:'stats.foo'}, {_ id:0, key:1}); db.foo.getIndexes (). forEach (function (f) {if (JSON.stringify (f.key)! =JSON.stringify (shardkey.key)) {printjson (shardkey.key); printjson (f.key); idx.push (f.name)}} ) 

Một cân nhắc khác liên quan đến đầu ra của $ indexStats, vì nó hiện trả về thống kê từ mỗi và mọi phân đoạn mà bộ sưu tập có sự hiện diện. Mặc dù không phổ biến, nhưng có những trường hợp (các) chỉ mục báo cáo là không được sử dụng trong một vài phân đoạn trong khi các phân đoạn khác đang sử dụng nó. Một khóa phân đoạn kém có thể là nguyên nhân nhưng tình huống phổ biến nhất được đặt tên là "bao gồm các chỉ mục".

Dưới đây là một ví dụ để hiểu rõ hơn về việc bao gồm các chỉ mục:Các chỉ mục {a:1} và {a:1, b:1} đều có thể phân phát đối sánh bình đẳng trên trường ‘a’. Nếu trình tối ưu hóa của shardA chọn {a:1} và trình tối ưu hóa của shardB chọn {a:1, b:1}, cả hai chỉ mục sẽ báo cáo là không được sử dụng cho ít nhất một phân đoạn.

Thách thức là tìm ra chỉ mục nào không được sử dụng trên toàn cầu. Thay thế phần tổng hợp (tiếp theo là vòng lặp forEach) của tập lệnh đang xem xét 2 (lần đọc thứ cấp) bằng tập lệnh sau sẽ thực hiện công việc:

 db.foo.aggregate ([{$ indexStats:{}}, {$ group:{_id:"$ name", number:{$ sum:"$ accesses.ops"}}}]) .forEach ( function (f) {if (f.number> 0) {var index =idx.indexOf (f._id); if (index> -1) {idx.splice (index, 1);};}})  

Một thách thức khác là khám phá các chỉ mục đang được sử dụng một phần. Phần thông tin này có thể hữu ích khi nói đến các chỉ mục thừa hoặc trục trặc trong việc xác định chỉ mục. Sử dụng mảng idx, tập hợp / tập lệnh sau được điền với các chỉ mục không được sử dụng trên toàn cầu và báo cáo các chỉ mục được sử dụng một phần:

 db.foo.aggregate ([{$ indexStats:{}}, {$ match:{name:{$ nin:idx}, "accesses.ops":0}}]). forEach (function (f) {print ("Index" + f.name + "báo cáo một phần không được sử dụng trên shard / host" + f.host)}) 

Cân nhắc 6:Các chỉ mục ít được sử dụng nhất

Việc phát hiện và loại bỏ các chỉ mục không sử dụng là rất quan trọng nhưng đánh giá các chỉ mục ít được sử dụng nhất cũng rất quan trọng. Nếu chỉ mục chỉ được truy cập một hoặc hai lần trong thời gian một tuần hoặc vài tháng, điều đó có thể có nghĩa là chỉ mục đó không cần thiết hoặc không có lợi cho khối lượng công việc của bạn. Luôn luôn là một phương pháp hay để kiểm tra định kỳ các chỉ mục ít được sử dụng nhất bằng cách sử dụng tổng hợp sau:

 db.foo.aggregate ([{$ indexStats:{}}, {$ match:{"accesses.ops":{$ gt:0}}}, {$ group:{_id:"$ name", số:{$ sum:"$ accesses.ops"}}}, {$ sort:{number:1}}]) 

Sau đó, thực hiện các hành động thích hợp có thể là bỏ (các) chỉ mục, thay đổi định nghĩa (các) chỉ mục hoặc thậm chí thay đổi logic lược đồ / ứng dụng của bạn để làm cho (các) chỉ mục trở nên thừa.

Chúng tôi ở đây vì bạn

Chúng tôi ở đây để giúp bạn xóa chỉ mục cho các phiên bản MongoDB của bạn. Tất cả những gì bạn phải làm là tạo một vé đến support@objectrocket.com và để chúng tôi giúp bạn cải thiện chỉ số của mình!