Cách nhanh nhất để viết nhiều tài liệu cho Firestore là gì?


Câu trả lời:


26

TL; DR: Cách nhanh nhất để thực hiện tạo ngày hàng loạt trên Firestore là bằng cách thực hiện các thao tác ghi riêng lẻ song song.

Viết 1.000 tài liệu cho Firestore mất:

  1. ~105.4s khi sử dụng các thao tác ghi riêng lẻ tuần tự
  2. ~ 2.8s khi sử dụng (2) thao tác ghi theo đợt
  3. ~ 1.5s khi sử dụng các thao tác ghi riêng lẻ song song

Có ba cách phổ biến để thực hiện một số lượng lớn thao tác ghi trên Firestore.

  1. Thực hiện từng thao tác viết riêng lẻ theo trình tự.
  2. Sử dụng các thao tác ghi theo đợt.
  3. Thực hiện các thao tác viết riêng lẻ song song.

Chúng tôi sẽ điều tra lần lượt từng cái bên dưới, sử dụng một loạt dữ liệu tài liệu ngẫu nhiên.


Hoạt động viết tuần tự cá nhân

Đây là giải pháp đơn giản nhất có thể:

async function testSequentialIndividualWrites(datas) {
  while (datas.length) {
    await collection.add(datas.shift());
  }
}

Chúng tôi lần lượt viết từng tài liệu cho đến khi chúng tôi viết mọi tài liệu. Và chúng tôi chờ cho mỗi thao tác ghi hoàn thành trước khi bắt đầu thao tác ghi tiếp theo.

Viết 1.000 tài liệu mất khoảng 105 giây với phương pháp này, do đó, thông lượng là khoảng 10 tài liệu viết mỗi giây .


Sử dụng thao tác ghi theo đợt

Đây là giải pháp phức tạp nhất.

async function testBatchedWrites(datas) {
  let batch = admin.firestore().batch();
  let count = 0;
  while (datas.length) {
    batch.set(collection.doc(Math.random().toString(36).substring(2, 15)), datas.shift());
    if (++count >= 500 || !datas.length) {
      await batch.commit();
      batch = admin.firestore().batch();
      count = 0;
    }
  }
}

Bạn có thể thấy rằng chúng tôi tạo một BatchedWriteđối tượng bằng cách gọi batch(), điền vào đó cho đến khi dung lượng tối đa 500 tài liệu của nó, sau đó viết nó cho Firestore. Chúng tôi cung cấp cho mỗi tài liệu một tên được tạo tương đối có khả năng là duy nhất (đủ tốt cho thử nghiệm này).

Viết 1.000 tài liệu mất khoảng 2,8 giây với phương pháp này, do đó, thông lượng là khoảng 357 tài liệu viết mỗi giây .

Đó là khá nhanh hơn một chút so với viết cá nhân tuần tự. Trên thực tế: nhiều nhà phát triển sử dụng phương pháp này vì họ cho rằng nó nhanh nhất, nhưng vì kết quả ở trên đã cho thấy điều này không đúng. Và mã là phức tạp nhất, do hạn chế kích thước trên các lô.


Song song hoạt động viết cá nhân

Tài liệu của Firestore nói điều này về hiệu suất để thêm nhiều dữ liệu :

Để nhập dữ liệu số lượng lớn, hãy sử dụng thư viện máy khách với ghi riêng lẻ. Viết theo lô thực hiện tốt hơn ghi tuần tự nhưng không tốt hơn ghi song song.

Chúng tôi có thể thử nghiệm điều đó với mã này:

async function testParallelIndividualWrites(datas) {
  await Promise.all(datas.map((data) => collection.add(data)));
}

Mã này khởi addđộng các hoạt động nhanh nhất có thể, và sau đó sử dụng Promise.all()để đợi cho đến khi tất cả hoàn thành. Với cách tiếp cận này, các hoạt động có thể chạy song song.

Viết 1.000 tài liệu mất khoảng 1,5 giây với phương pháp này, do đó, thông lượng là khoảng 667 tài liệu viết mỗi giây .

Sự khác biệt không lớn bằng giữa hai cách tiếp cận đầu tiên, nhưng nó vẫn nhanh hơn 1,8 lần so với cách viết theo đợt.


Một vài lưu ý:

  • Bạn có thể tìm thấy mã đầy đủ của bài kiểm tra này trên Github .
  • Mặc dù thử nghiệm đã được thực hiện với Node.js, nhưng bạn có thể nhận được kết quả tương tự trên tất cả các nền tảng mà SDK quản trị hỗ trợ.
  • Tuy nhiên, đừng thực hiện chèn hàng loạt bằng SDK khách, vì kết quả có thể rất khác nhau và ít dự đoán hơn.
  • Như thường lệ, hiệu suất thực tế phụ thuộc vào máy của bạn, băng thông và độ trễ của kết nối internet của bạn và nhiều yếu tố khác. Dựa trên những người bạn cũng có thể thấy sự khác biệt về sự khác biệt, mặc dù tôi hy vọng việc đặt hàng vẫn giữ nguyên.
  • Nếu bạn có bất kỳ ngoại lệ nào trong các thử nghiệm của riêng bạn hoặc tìm thấy kết quả hoàn toàn khác nhau, hãy để lại nhận xét bên dưới.
  • Batches viết là nguyên tử. Vì vậy, nếu bạn có sự phụ thuộc giữa các tài liệu và tất cả các tài liệu phải được viết, hoặc không ai trong số chúng phải được viết, bạn nên sử dụng một cách viết theo đợt.

1
Điều này là siêu thú vị, cảm ơn bạn đã làm công việc! OOC, bạn đã thử chạy song song việc ghi theo đợt chưa? Rõ ràng, trong trường hợp đó, bạn sẽ cần phải chắc chắn hơn nữa để tránh bất kỳ tài liệu nào nằm trong cả hai đợt.
robsiemb

1
Tôi chuẩn bị thử nghiệm viết theo đợt song song, nhưng đã hết hạn ngạch (đó là một dự án miễn phí và tôi quá lười để nâng cấp). Hôm nay là một ngày khác, vì vậy tôi có thể thử lại và cập nhật câu trả lời của mình nếu nó quan trọng.
Frank van Puffelen

2
@robsiemb Mình mới thử nghiệm viết song song. Hiệu suất rất giống với cách viết song song riêng lẻ, vì vậy tôi nói rằng chúng được buộc đầu tiên trong các thử nghiệm của tôi. Tôi hy vọng rằng việc viết theo đợt có thể xấu đi nhanh hơn do tính chất chúng được xử lý ở mặt sau. Kết hợp với mã phức tạp hơn nhiều, tôi vẫn khuyên bạn chỉ nên sử dụng chúng cho tính nguyên tử của chúng chứ không phải lợi thế về hiệu suất nhận thức nhưng không tồn tại.
Frank van Puffelen

@FrankvanPuffelen viết song song cũng sẽ nhanh hơn nếu tôi "đặt" tài liệu thay vì "thêm" tài liệu? Ý tôi là, db.collection ('thành phố'). Doc ('LA'). Set (dữ liệu) thay vì db.collection ('thành phố'). Add (data)
alek6dj

Gọi add()không làm gì khác hơn là tạo một ID duy nhất (hoàn toàn là phía máy khách), theo sau là một set()thao tác. Vì vậy, kết quả nên giống nhau. Nếu đó không phải là những gì bạn quan sát, hãy đăng một câu hỏi mới với trường hợp tối thiểu tái tạo những gì bạn đã thử.
Frank van Puffelen
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.