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

Làm cách nào để tăng hiệu suất của hoạt động cập nhật trong Mongo?

Khi cập nhật theo cách hiện có, bạn cần truy xuất nội dung tài liệu để kiểm tra và thực hiện các sửa đổi đó. MongoDB không có phép toán nguyên tử nào hoạt động trên các giá trị hiện có theo cách bạn muốn, vì vậy, tất nhiên là bắt buộc phải lặp lại.

Không có sự khác biệt thực sự nào trong phần "truy vấn" về cách bạn đối sánh trên biểu thức chính quy giữa hai phiên bản câu lệnh của bạn. Không có vấn đề gì, nội dung vẫn được chuyển đổi thành BSON trước khi gửi đến máy chủ, vì vậy nếu bạn sử dụng trình tạo biểu thức tiêu chuẩn hoặc tài liệu BSON trực tiếp thì ít có hậu quả.

Nhưng dựa trên những cải tiến về hiệu suất có thể được thực hiện.

Sử dụng Thao tác hàng loạt để cập nhật

Như đã nêu, Thao tác hàng loạt là cách bạn nên cập nhật khi lặp lại danh sách như vậy và bạn cũng "nên" sử dụng con trỏ thay vì chuyển đổi tất cả kết quả thành danh sách, vì nó sẽ lưu trên bộ nhớ.

Chuyển tất cả các khai báo kiểu cụ thể và chỉ biểu diễn dưới dạng BsonDocument (điều này có thể sẽ giúp bạn tiết kiệm chi phí sắp xếp, nhưng không cần thiết) thì quy trình ví dụ cơ bản sẽ là:

var pattern = @"(?si)<([^\s<]*workUnit[^\s<]*)>.*?</\1>";
var filter = Builders<JobInfoRecord>.Filter.Regex(x => x.SerializedBackgroundJobInfo,
                                              new BsonRegularExpression(pattern, "i"));


var ops = new List<WriteModel<BsonDocument>>();
var writeOptions = new BulkWriteOptions() { IsOrdered = false };

using ( var cursor = await records.FindAsync<BsonDocument>(filter))
{
    while ( await cursor.MoveNextAsync())
    {
        foreach( var doc in cursor.Current )
        {
            // Replace inspected value
            var updatedJobInfo = Regex.Replace(doc.SerializedBackgroundJobInfo, pattern, "<$1></$1>");

            // Add WriteModel to list
            ops.Add(
                new UpdateOneModel<BsonDocument>(
                    Builders<BsonDocument>.Filter.Eq("JobTypeValue", doc.JobTypeValue),
                    Builders<BsonDocument>.Update.Set("SerializedBackgroundJobInfo", updatedJobInfo)
                )
            );

            // Execute once in every 1000 and clear list
            if (ops.Count == 1000)
            {
                BulkWriteResult<BsonDocument> result = await records.BulkWriteAsync(ops,writeOptions);
                ops = new List<WriteModel<BsonDocument>>();
            }
        }
    }

    // Clear any remaining
    if (ops.Count > 0 )
    {
        BulkWriteResult<BsonDocument> result = await records.BulkWriteAsync(ops,writeOptions);
    }

}

Vì vậy, thay vì đưa ra yêu cầu đối với cơ sở dữ liệu cho mọi tài liệu được truy xuất từ ​​truy vấn, bạn tạo một List của WriteModel các hoạt động thay thế.

Khi danh sách này đã tăng đến một giá trị hợp lý (trong ví dụ này là 1000), bạn cam kết hoạt động ghi vào máy chủ trong một yêu cầu và phản hồi duy nhất cho tất cả các hoạt động theo đợt. Ở đây chúng tôi sử dụng BulkWriteAsync .

Bạn có thể tạo các lô với kích thước lớn hơn 1000 nếu muốn, nhưng nhìn chung đó là một con số hợp lý để giải quyết. Giới hạn cứng thực sự duy nhất là giới hạn BSON 16MB, vì tất cả các yêu cầu vẫn thực sự là tài liệu BSON nên điều này vẫn được áp dụng. Dù sao thì cũng cần rất nhiều yêu cầu để đạt đến 16MB, nhưng cũng có một sự phù hợp trở ngại cần xem xét về cách yêu cầu sẽ được xử lý khi nó thực sự đến máy chủ, như đã ghi:

"Mỗi nhóm hoạt động có thể có tối đa 1000 hoạt động. Nếu một nhóm vượt quá giới hạn này, MongoDB sẽ chia nhóm thành các nhóm nhỏ hơn 1000 hoặc ít hơn. Ví dụ:nếu danh sách hoạt động hàng loạt bao gồm 2000 hoạt động chèn, MongoDB tạo 2 nhóm, mỗi nhóm có 1000 thao tác. "

Do đó, bằng cách giữ kích thước yêu cầu ở cùng mức độ máy chủ sẽ xử lý nó, bạn cũng nhận được lợi ích từ yield trong đó "nhiều lô" trên thực tế có thể hoạt động trong các kết nối song song với máy chủ, thay vì để máy chủ thực hiện việc tách và xếp hàng.

Kết quả trả về là của BulkWriteResult sẽ chứa thông tin về số lượng "kết quả phù hợp" và "sửa đổi", v.v. từ loạt hoạt động được gửi.

Đương nhiên vì các hoạt động theo "lô", nên kiểm tra ở cuối vòng lặp để xem có bất kỳ hoạt động "theo lô" nào nữa tồn tại trong danh sách hay không và sau đó tất nhiên gửi theo cách tương tự.

Cũng lưu ý IsOrdered = false dưới dạng BulkWriteOptions có nghĩa là lô hoạt động không thực sự được thực thi theo thứ tự nối tiếp, có nghĩa là máy chủ trên thực tế có thể chạy các thẻ "song song". Điều này có thể tạo ra những cải tiến tốc độ "khổng lồ" mà thứ tự cam kết không được yêu cầu. Mặc định là gửi "có thứ tự" và theo thứ tự.

Không bắt buộc phải đặt tùy chọn này, nhưng nếu đơn đặt hàng của bạn không quan trọng (điều này không nên xảy ra trong trường hợp này vì không có yêu cầu hoạt động nào khác ở đây phụ thuộc vào sửa đổi hiện hành của tài liệu) thì cải tiến bạn nhận được là đáng giá.

Tất cả những gì điều này là "giảm" số lượng yêu cầu thực tế được thực hiện đến máy chủ. Việc gửi các bản cập nhật và chờ phản hồi mất nhiều thời gian và trong các hoạt động lớn là một công việc rất tốn kém. Đó là những gì Hoạt động hàng loạt có nghĩa là phải giải quyết, bằng cách áp dụng một số hoạt động trong một yêu cầu.

Giảm chi phí đó là một hiệu suất tăng "rất lớn". Đó là lý do tại sao bạn sử dụng cái này.




  1. Redis
  2.   
  3. MongoDB
  4.   
  5. Memcached
  6.   
  7. HBase
  8.   
  9. CouchDB
  1. 5 cách để kiểm tra kích thước của một bộ sưu tập trong MongoDB

  2. Các yếu tố hoạt động cần xem xét trong quá trình tạo mô hình dữ liệu MongoDB

  3. Lọc mảng bằng toán tử $ in trong giai đoạn $ project

  4. Mức độ không an toàn của MongoDB và Cách tránh chúng

  5. Làm cách nào để chuyển đổi một trường boolean trong một tài liệu với phép toán nguyên tử?