2012-10-01 22 views
14

Đây là từ django docs on the queryset iterator() method:Khi sử dụng hay không sử dụng iterator() trong ORM django

Một QuerySet thường lưu trữ kết quả của nó trong nội bộ để đánh giá lặp đi lặp lại không dẫn đến truy vấn bổ sung. Ngược lại, iterator() sẽ đọc kết quả trực tiếp, mà không thực hiện bất kỳ bộ nhớ đệm nào ở cấp QuerySet (trong nội bộ, các defaul t iterator calls iterator() và lưu trữ giá trị trả về). Đối với một QuerySet mà trả về một số lượng lớn các đối tượng mà bạn chỉ cần truy cập một lần, điều này có thể dẫn đến hiệu suất tốt hơn và giảm đáng kể bộ nhớ.

Sau khi đọc, tôi vẫn còn bối rối: Dòng về hiệu suất tăng và giảm bộ nhớ cho thấy chúng ta chỉ nên sử dụng phương pháp iterator(). Ai đó có thể đưa ra một số ví dụ về trường hợp tốt và xấu iterator() sử dụng?

Ngay cả khi kết quả truy vấn không được lưu trong bộ nhớ cache, nếu chúng thực sự muốn truy cập vào các mô hình nhiều lần, thì không ai có thể làm như sau?

saved_queries = list(Model.objects.all().iterator()) 
+0

Tôi nghĩ rằng đó là vấn đề về kích thước mô hình ... nếu lớn của nó thì có thể bạn không muốn bị treo cổ trong bộ nhớ ... –

Trả lời

23

Lưu ý phần đầu tiên của câu thì gọi ra: For a QuerySet which returns a large number of objects that you only need to access once

Vì vậy, ngược lại của việc này là: nếu bạn cần phải sử dụng một bộ kết quả, và họ không quá nhiều như gây ra vấn đề về bộ nhớ thì bạn không nên sử dụng iterator. Vì chuyến đi vòng cơ sở dữ liệu bổ sung là luôn luôn sẽ giảm hiệu suất của bạn so với sử dụng kết quả được lưu trong bộ nhớ cache.

Bạn có thể buộc QuerySet của bạn được đánh giá vào một danh sách nhưng:

  • nó đòi hỏi gõ nhiều hơn chỉ saved_queries = Model.objects.all()
  • nói rằng bạn đang paginating kết quả trên một trang web: bạn sẽ phải buộc tất cả các kết quả vào bộ nhớ (quay lại các vấn đề bộ nhớ có thể) thay vì cho phép người truy cập tiếp theo chọn 20 lát kết quả cần
  • QuerySets are lazy, vì vậy bạn có thể có bộ xử lý ngữ cảnh, đặt QuerySet vào ngữ cảnh của mọi yêu cầu nhưng chỉ được đánh giá khi bạn truy cập nó trên certa trong các yêu cầu nhưng nếu bạn đã buộc phải đánh giá rằng việc truy cập cơ sở dữ liệu xảy ra theo yêu cầu

Trường hợp ứng dụng web điển hình là dành cho các bộ kết quả tương đối nhỏ (chúng phải được gửi đến trình duyệt một cách kịp thời, để phân trang hoặc kỹ thuật tương tự được sử dụng để giảm khối lượng dữ liệu nếu cần), vì vậy thường hành vi tiêu chuẩn QuerySet là những gì bạn muốn. Vì bạn không nghi ngờ gì, bạn phải store the QuerySet in a variable để có được lợi ích của bộ nhớ đệm.

Sử dụng tốt trình vòng lặp: xử lý các kết quả chiếm một lượng lớn bộ nhớ khả dụng (nhiều đối tượng nhỏ hoặc ít đối tượng lớn hơn). Theo kinh nghiệm của tôi, điều này thường có trong các lệnh quản lý khi thực hiện xử lý dữ liệu nặng.

0

Tôi đồng ý với Steven và tôi muốn có một quan sát:

  • "nó đòi hỏi gõ nhiều hơn chỉ saved_queries = Model.objects.all()".Có, nhưng có một sự khác biệt lớn tại sao bạn nên sử dụng danh sách (Model.objcts.all()). Để tôi đưa cho bạn một ví dụ, nếu bạn đặt cái được gán cho một biến, nó sẽ thực hiện truy vấn và lưu nó ở đó, hãy tưởng tượng bạn có bản ghi + 1 triệu, vậy nghĩa là bạn sẽ có + 1 triệu bản ghi trong danh sách bạn có thể hoặc không thể sử dụng ngay sau đó, vì vậy tôi khuyên bạn chỉ nên sử dụng như Steven đã nói, chỉ sử dụng Model.objects.all(), vì điều này được gán cho một biến, nó sẽ không thực thi cho đến khi bạn gọi biến, tiết kiệm bạn gọi DB.

  • Bạn nên sử dụng prefetch_related() để giúp bạn không thực hiện nhiều cuộc gọi vào DB và do đó, nó sẽ sử dụng tra cứu ngược lại để giúp bạn và tiết kiệm thời gian.