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

Cách tối ưu hóa hiệu suất của MongoDB

Hiệu suất cơ sở dữ liệu xuất sắc rất quan trọng khi bạn đang phát triển ứng dụng với MongoDB. Đôi khi quy trình cung cấp dữ liệu tổng thể có thể bị giảm chất lượng do một số lý do, một số lý do trong số đó bao gồm:

  • Các mẫu thiết kế giản đồ không phù hợp
  • Sử dụng không đúng cách hoặc không sử dụng các chiến lược lập chỉ mục
  • Phần cứng không phù hợp
  • Độ trễ sao chép
  • Kỹ thuật truy vấn hoạt động kém

Một số trở ngại này có thể buộc bạn phải tăng tài nguyên phần cứng trong khi những người khác thì không. Ví dụ:cấu trúc truy vấn kém có thể dẫn đến việc xử lý truy vấn mất nhiều thời gian, gây ra độ trễ bản sao và thậm chí có thể mất một số dữ liệu. Trong trường hợp này, người ta có thể nghĩ rằng có thể bộ nhớ lưu trữ không đủ và nó có thể cần mở rộng quy mô. Bài viết này thảo luận về các quy trình thích hợp nhất mà bạn có thể sử dụng để tăng hiệu suất của cơ sở dữ liệu MongoDB của mình.

Thiết kế lược đồ

Về cơ bản, hai mối quan hệ lược đồ được sử dụng phổ biến nhất là ...

  • Một-một-vài
  • Một-nhiều

Mặc dù thiết kế giản đồ hiệu quả nhất là mối quan hệ Một-Nhiều, nhưng mỗi thiết kế đều có những ưu điểm và hạn chế riêng.

Một-một-vài

Trong trường hợp này, đối với một trường nhất định, có các tài liệu được nhúng nhưng chúng không được lập chỉ mục với danh tính đối tượng.

Đây là một ví dụ đơn giản:

{
      userName: "Brian Henry",
      Email : "[email protected]",
      grades: [
             {subject: ‘Mathematics’,  grade: ‘A’},
             {subject: English,  grade: ‘B’},
      ]
}

Một lợi thế của việc sử dụng mối quan hệ này là bạn có thể lấy các tài liệu nhúng chỉ với một truy vấn duy nhất. Tuy nhiên, từ quan điểm truy vấn, bạn không thể truy cập một tài liệu nhúng duy nhất. Vì vậy, nếu bạn không tham khảo các tài liệu nhúng một cách riêng biệt, sẽ là tối ưu khi sử dụng thiết kế lược đồ này.

Một-nhiều

Đối với mối quan hệ này, dữ liệu trong một cơ sở dữ liệu có liên quan đến dữ liệu trong một cơ sở dữ liệu khác. Ví dụ:bạn có thể có một cơ sở dữ liệu cho người dùng và một cơ sở dữ liệu khác cho các bài đăng. Vì vậy, nếu người dùng tạo một bài đăng, nó sẽ được ghi lại với id người dùng.

Lược đồ người dùng

{ 
    Full_name: “John Doh”,
    User_id: 1518787459607.0
}

Lược đồ bài đăng

{
    "_id" : ObjectId("5aa136f0789cf124388c1955"),
    "postTime" : "16:13",
    "postDate" : "8/3/2018",
    "postOwnerNames" : "John Doh",
    "postOwner" : 1518787459607.0,
    "postId" : "1520514800139"
}

Ưu điểm của thiết kế lược đồ này là các tài liệu được coi là độc lập (có thể được chọn riêng). Một ưu điểm khác là thiết kế này cho phép người dùng các id khác nhau chia sẻ thông tin từ lược đồ bài đăng (do đó có tên là Một-nhiều) và đôi khi có thể là lược đồ “N-to-N” - về cơ bản mà không cần sử dụng phép nối bảng. Hạn chế với thiết kế lược đồ này là bạn phải thực hiện ít nhất hai truy vấn để tìm nạp hoặc chọn dữ liệu trong bộ sưu tập thứ hai.

Do đó, cách lập mô hình dữ liệu sẽ phụ thuộc vào kiểu truy cập của ứng dụng. Bên cạnh đó, bạn cần xem xét thiết kế lược đồ mà chúng ta đã thảo luận ở trên.

Kỹ thuật tối ưu hóa cho thiết kế lược đồ

  1. Sử dụng tính năng nhúng tài liệu càng nhiều càng tốt vì nó làm giảm số lượng truy vấn bạn cần chạy cho một tập dữ liệu cụ thể.

  2. Không sử dụng chuẩn hóa cho các tài liệu được cập nhật thường xuyên. Nếu anfield thường xuyên được cập nhật, thì sẽ có nhiệm vụ tìm tất cả các trường hợp cần được cập nhật. Điều này sẽ dẫn đến việc xử lý truy vấn chậm, do đó lấn át ngay cả những giá trị liên quan đến việc không chuẩn hóa.

  3. Nếu có nhu cầu tìm nạp một tài liệu riêng biệt, thì không cần sử dụng tính năng nhúng vì các truy vấn phức tạp như kết nối tổng hợp sẽ mất nhiều thời gian hơn để thực thi.

  4. Nếu mảng tài liệu cần nhúng đủ lớn, đừng nhúng chúng. Sự tăng trưởng của mảng ít nhất phải có giới hạn ràng buộc.

Lập chỉ mục thích hợp

Đây là phần quan trọng hơn của việc điều chỉnh hiệu suất và đòi hỏi một người phải có hiểu biết toàn diện về các truy vấn ứng dụng, tỷ lệ đọc để ghi và hệ thống của bạn có bao nhiêu bộ nhớ trống. Nếu bạn sử dụng chỉ mục, thì truy vấn sẽ quét chỉ mục chứ không phải tập hợp.

Một chỉ mục xuất sắc là một chỉ mục liên quan đến tất cả các trường được quét bởi một truy vấn. Đây được gọi là chỉ số kết hợp.

Để tạo một chỉ mục cho một trường, bạn có thể sử dụng mã này:

db.collection.createIndex({“fields”: 1})

Đối với một chỉ mục kết hợp, để tạo lập chỉ mục:

db.collection.createIndex({“filed1”: 1, “field2”:  1})

Bên cạnh việc truy vấn nhanh hơn bằng cách sử dụng lập chỉ mục, có một lợi thế bổ sung của các hoạt động khác như sắp xếp, mẫu và giới hạn. Ví dụ:nếu tôi thiết kế giản đồ của mình dưới dạng {f:1, m:1}, tôi có thể thực hiện thêm một thao tác khác ngoài find as

db.collection.find( {f: 1} ).sort( {m: 1} )

Đọc dữ liệu từ RAM hiệu quả hơn đọc cùng một dữ liệu từ đĩa. Vì lý do này, bạn nên đảm bảo rằng chỉ mục của bạn nằm hoàn toàn trong RAM. Để lấy indexSize hiện tại của bộ sưu tập của bạn, hãy chạy lệnh:

db.collection.totalIndexSize()

Bạn sẽ nhận được một giá trị như 36864 byte. Giá trị này cũng không được chiếm một tỷ lệ lớn của kích thước RAM tổng thể, vì bạn cần đáp ứng nhu cầu của toàn bộ tập hợp làm việc của máy chủ.

Một truy vấn hiệu quả cũng sẽ nâng cao tính chọn lọc. Tính chọn lọc có thể được định nghĩa là khả năng của một truy vấn để thu hẹp kết quả bằng cách sử dụng chỉ mục. Để bảo mật hơn, các truy vấn của bạn nên giới hạn số lượng tài liệu có thể có với trường được lập chỉ mục. Tính chọn lọc chủ yếu được liên kết với một chỉ số hợp chất bao gồm một trường có độ chọn lọc thấp và một trường khác. Ví dụ:nếu bạn có dữ liệu này:

{ _id: ObjectId(), a: 6, b: "no", c: 45 }
{ _id: ObjectId(), a: 7, b: "gh", c: 28 }
{ _id: ObjectId(), a: 7, b: "cd", c: 58 }
{ _id: ObjectId(), a: 8, b: "kt", c: 33 }

Truy vấn {a:7, b:“cd”} sẽ quét qua 2 tài liệu để trả về 1 tài liệu phù hợp. Tuy nhiên, nếu dữ liệu cho giá trị a được phân phối đồng đều, tức là

{ _id: ObjectId(), a: 6, b: "no", c: 45 }
{ _id: ObjectId(), a: 7, b: "gh", c: 28 }
{ _id: ObjectId(), a: 8, b: "cd", c: 58 }
{ _id: ObjectId(), a: 9, b: "kt", c: 33 }

Truy vấn {a:7, b:“cd”} sẽ quét qua 1 tài liệu và trả về tài liệu này. Do đó, điều này sẽ mất thời gian ngắn hơn so với cấu trúc dữ liệu đầu tiên.

ClusterControlSingle Console cho Toàn bộ Cơ sở dữ liệu Cơ sở hạ tầng của bạnTìm hiểu những tính năng mới khác trong ClusterControlInstall ClusterControl MIỄN PHÍ

Cung cấp tài nguyên

Bộ nhớ lưu trữ không đủ, RAM và các thông số hoạt động khác có thể làm giảm đáng kể hiệu suất của MongoDB. Ví dụ:nếu số lượng kết nối của người dùng rất lớn, nó sẽ cản trở khả năng xử lý các yêu cầu của ứng dụng máy chủ một cách kịp thời. Như đã thảo luận trong Những điều quan trọng cần theo dõi trong MongoDB, bạn có thể có cái nhìn tổng quan về những tài nguyên giới hạn mà bạn có và cách bạn có thể chia tỷ lệ chúng cho phù hợp với thông số kỹ thuật của mình. Đối với một số lượng lớn các yêu cầu ứng dụng đồng thời, hệ thống cơ sở dữ liệu sẽ bị quá tải để theo kịp nhu cầu.

Trễ sao chép

Đôi khi bạn có thể nhận thấy một số dữ liệu bị thiếu trong cơ sở dữ liệu của mình hoặc khi bạn xóa một thứ gì đó, nó lại xuất hiện. Bạn có thể có lược đồ được thiết kế tốt, lập chỉ mục phù hợp và đủ tài nguyên nhiều nhất có thể, lúc đầu ứng dụng của bạn sẽ chạy trơn tru mà không có bất kỳ trục trặc nào nhưng đến một lúc nào đó bạn nhận thấy các vấn đề được đề cập sau này. MongoDB dựa trên khái niệm sao chép trong đó dữ liệu được sao chép dư thừa để đáp ứng một số tiêu chí thiết kế. Một giả định với điều này là quá trình này là tức thời. Tuy nhiên, một số chậm trễ có thể xảy ra có thể do lỗi mạng hoặc lỗi chưa được khắc phục. Tóm lại, sẽ có một khoảng cách lớn giữa thời gian mà một thao tác được xử lý trên nút chính và thời gian nó sẽ được áp dụng trong nút phụ.

Sự thất bại với độ trễ của bản sao

  1. Dữ liệu không nhất quán. Điều này đặc biệt liên quan đến các hoạt động đọc được phân phối trên các thư thứ hai.

  2. Nếu khoảng cách trễ đủ rộng, thì rất nhiều dữ liệu chưa được giải thích có thể nằm trên nút chính và sẽ cần được điều chỉnh trong nút phụ. Tại một số thời điểm, điều này có thể không thực hiện được, đặc biệt là khi không thể khôi phục được nút chính.

  3. Việc không khôi phục được nút chính có thể buộc người ta phải chạy một nút có dữ liệu không được cập nhật và do đó có thể làm rơi toàn bộ cơ sở dữ liệu để khiến nút chính khôi phục.

Nguyên nhân gây ra lỗi nút phụ

  1. Công suất chính vượt trội so với nguồn phụ liên quan đến CPU, IOPS ổ đĩa và thông số kỹ thuật I / O mạng.

  2. Các thao tác ghi phức tạp. Ví dụ một lệnh như

    db.collection.update( { a: 7}  , {$set: {m: 4} }, {multi: true} )

    Nút chính sẽ ghi lại thao tác này trong oplog đủ nhanh. Tuy nhiên, đối với nút phụ, nó phải tìm nạp các hoạt động đó, đọc vào RAM bất kỳ chỉ mục và trang dữ liệu nào để đáp ứng một số thông số kỹ thuật tiêu chí như id. Vì nó phải làm điều này đủ nhanh để giữ tốc độ với nút chính thực hiện hoạt động, nếu số lượng hoạt động đủ lớn thì sẽ có độ trễ dự kiến.

  3. Khóa phụ khi tạo bản sao lưu. Trong trường hợp này, chúng tôi có thể quên tắt tính năng chính do đó sẽ tiếp tục hoạt động của nó như bình thường. Tại thời điểm khóa sẽ được phát hành, độ trễ sao chép sẽ có một khoảng cách lớn, đặc biệt là khi xử lý một lượng lớn dữ liệu sao lưu.

  4. Xây dựng chỉ mục. Nếu một chỉ mục tích tụ trong nút phụ, thì tất cả các hoạt động khác liên quan đến nó sẽ bị chặn. Nếu chỉ mục đang chạy lâu thì sẽ gặp phải lỗi trễ sao chép.

  5. Thứ cấp không kết nối. Đôi khi nút phụ có thể bị lỗi do ngắt kết nối mạng và điều này dẫn đến độ trễ sao chép khi nó được kết nối lại.

Cách giảm thiểu độ trễ sao chép

  • Sử dụng các chỉ mục duy nhất bên cạnh bộ sưu tập của bạn có trường _id. Điều này để tránh quá trình sao chép không hoàn toàn thất bại.

  • Xem xét các loại sao lưu khác như ảnh chụp nhanh hệ thống tệp và thời điểm không nhất thiết phải khóa.

  • Tránh tạo các chỉ mục lớn vì chúng gây ra hoạt động chặn nền.

  • Làm cho thứ cấp đủ mạnh. Nếu thao tác ghi có trọng lượng nhẹ, thì việc sử dụng các thiết bị thứ hai có năng lực kém sẽ tiết kiệm. Tuy nhiên, đối với tải trọng ghi lớn, nút phụ có thể tụt hậu so với nút chính. Để rõ ràng hơn, nút phụ phải có đủ băng thông để giúp đọc nhật ký đủ nhanh để giữ tốc độ của nó với nút chính.

Kỹ thuật truy vấn hiệu quả

Bên cạnh việc tạo các truy vấn được lập chỉ mục và sử dụng Tính chọn lọc truy vấn như đã thảo luận ở trên, bạn có thể sử dụng các khái niệm khác để khắc phục và làm cho các truy vấn của mình hiệu quả.

Tối ưu hóa truy vấn của bạn

  1. Sử dụng một truy vấn được bao phủ. Một truy vấn được bao phủ là một truy vấn luôn được chỉ mục đáp ứng hoàn toàn do đó không cần phải kiểm tra bất kỳ tài liệu nào. Do đó, truy vấn được đề cập phải có tất cả các trường như một phần của chỉ mục và do đó kết quả phải chứa tất cả các trường này.

    Hãy xem xét ví dụ này:

    {_id: 1, product: { price: 50 }

    Nếu chúng tôi tạo chỉ mục cho bộ sưu tập này dưới dạng

    {“product.price”: 1} 

    Xem xét một hoạt động tìm kiếm, thì chỉ mục này sẽ bao gồm truy vấn này;

    db.collection.find( {“product.price”: 50}, {“product.price”: 1, _id: 0}  )

    và chỉ trả lại giá trị và trường product.price.

  2. Đối với các tài liệu được nhúng, hãy sử dụng ký hiệu dấu chấm (.). Ký hiệu dấu chấm giúp truy cập các phần tử của một mảng và các trường của tài liệu nhúng.

    Truy cập một mảng:

    {
       prices: [12, 40, 100, 50, 40]  
    }

    Để chỉ định phần tử thứ tư chẳng hạn, bạn có thể viết lệnh sau:

    “prices.3”

    Truy cập một mảng đối tượng:

    {
    
       vehicles: [{name: toyota, quantity: 50},
                 {name: bmw, quantity: 100},
                 {name: subaru, quantity: 300}                    
    } 

    Để chỉ định trường tên trong mảng phương tiện, bạn có thể sử dụng lệnh này

    “vehicles.name”
  3. Kiểm tra xem một truy vấn có được bảo hiểm hay không. Để thực hiện việc này, hãy sử dụng db.collection.explain (). Chức năng này sẽ cung cấp thông tin về việc thực hiện các hoạt động khác - ví dụ:db.collection.explain (). tổng hợp (). Để tìm hiểu thêm về hàm giải thích, bạn có thể xem giải thích ().

Nói chung, kỹ thuật tối cao liên quan đến truy vấn là sử dụng các chỉ mục. Chỉ truy vấn một chỉ mục nhanh hơn nhiều so với truy vấn các tài liệu bên ngoài chỉ mục. Chúng có thể phù hợp với bộ nhớ do đó có sẵn trong RAM hơn là trong đĩa. Điều này giúp dễ dàng và đủ nhanh để tìm nạp chúng từ bộ nhớ.


  1. Redis
  2.   
  3. MongoDB
  4.   
  5. Memcached
  6.   
  7. HBase
  8.   
  9. CouchDB
  1. Truy vấn C # mongo với chuỗi json

  2. mongoDB:Tạo một ObjectId cho mỗi phần tử con mới được thêm vào trường mảng

  3. Có cách nào để cập nhật nguyên tử hai bộ sưu tập trong MongoDB không?

  4. Tổng quan về MongoDB Atlas:Phần thứ hai

  5. Cách phân tích mức sử dụng đĩa của vùng chứa Docker