জ্যাঙ্গো ক্যোয়ারীসেটে বনাম লেন গণনা করুন


93

জ্যাঙ্গোতে, আমার দেওয়া হয়েছে যে আমি QuerySetপুনরাবৃত্তি করতে যাচ্ছি এবং ফলাফলগুলি মুদ্রণ করতে যাচ্ছি, অবজেক্টগুলি গণনা করার জন্য সেরা বিকল্পটি কী? len(qs)বা qs.count()?

(এছাড়াও একই পুনরাবৃত্তিতে অবজেক্টগুলি গণনা করা কোনও বিকল্প নয় given)


4
আকর্ষণীয় প্রশ্ন। আমি এটি প্রোফাইল করার পরামর্শ দিচ্ছি .. আমি খুব আগ্রহী হব! সম্পূর্ণ মূল্যায়নকৃত বস্তুর উপর লেন () ল্যাণ্ডের ওভারহেড রয়েছে কিনা তা জানার জন্য আমি পাইথন সম্পর্কে যথেষ্ট পরিমাণে জানি না। এটি গণনার চেয়ে দ্রুত হতে পারে!
যুজি 'টোমিটা' টোমিতা

উত্তর:


132

যদিও জ্যাঙ্গো ডক্সcount পরিবর্তে ব্যবহার করার পরামর্শ দেয় len:

দ্রষ্টব্য: len()আপনি যা করতে চান তা যদি সেটে রেকর্ডের সংখ্যা নির্ধারণ করে তবে কোয়েরিসেটে ব্যবহার করবেন না । এটি এসকিউএল এর সাহায্যে ডাটাবেস স্তরে একটি গণনা পরিচালনা করতে অনেক বেশি দক্ষ SELECT COUNT(*)এবং জ্যাঙ্গো count()ঠিক এই কারণে একটি পদ্ধতি সরবরাহ করে ।

আপনি এই QuerySet যাহাই হউক না কেন iterating যেহেতু, ফলাফলের ক্যাশে করা হবে (যদি না আপনি ব্যবহার করছেন iterator), এবং তাই এটি ব্যবহার করা বাঞ্ছনীয় হতে হবে len, যেহেতু এই এড়াতে ফলাফল একটি আলাদা নম্বর পুনরুদ্ধারের এর সম্ভবত আবার ডাটাবেসের আঘাত, এবং এছাড়াও !) ।
আপনি যদি ব্যবহার করে থাকেন iteratorতবে আমি একই কারণে আপনি কাউন্টের পরিবর্তনের (গণনা ব্যবহার না করে) পুনরাবৃত্তি করার সাথে সাথে একটি গণনা ভেরিয়েবল অন্তর্ভুক্ত করার পরামর্শ দেব।


60

এর মধ্যে বাছাই করা len()এবং count()পরিস্থিতির উপর নির্ভর করে এবং তারা কীভাবে এগুলি সঠিকভাবে ব্যবহার করতে কাজ করে তা গভীরভাবে বুঝতে পারা উচিত।

আমাকে আপনাকে কয়েকটি পরিস্থিতি সরবরাহ করতে দিন:

  1. (অত্যন্ত গুরুত্বপূর্ণ) যখন আপনি কেবলমাত্র উপাদানের সংখ্যা জানতে চান এবং আপনি যে কোনও উপায়ে এটি ব্যবহার করা গুরুত্বপূর্ণ হিসাবে তাদের প্রক্রিয়া করার পরিকল্পনা করেন না count():

    করুন: queryset.count() - এটি একক SELECT COUNT(*) some_tableক্যোয়ারী করবে, সমস্ত গণনা আরডিবিএমএসের দিকে চালিত হবে, পাইথনকে কেবল ও (1) এর নির্ধারিত ব্যয়ের সাথে ফলাফলের সংখ্যাটি উদ্ধার করতে হবে

    করবেন না: len(queryset) - এটি SELECT * FROM some_tableকোয়েরি সম্পাদন করবে , পুরো টেবিল ও (এন) এনেছে এবং এটি সংরক্ষণের জন্য অতিরিক্ত ও (এন) মেমরির প্রয়োজন হবে। এটি করা যেতে পারে সবচেয়ে খারাপ

  2. আপনি যেভাবে যাইহোক ক্যোয়ারেটটি আনার ইচ্ছাকৃত তা ব্যবহার করা কিছুটা ভাল len()যা কোনও অতিরিক্ত ডাটাবেস ক্যোয়ারির কারণ হবে না count():

    len(queryset) # fetching all the data - NO extra cost - data would be fetched anyway in the for loop
    
    for obj in queryset: # data is already fetched by len() - using cache
        pass
    

    গণনা:

    queryset.count() # this will perform an extra db query - len() did not
    
    for obj in queryset: # fetching data
        pass
    
  3. প্রত্যাবর্তিত ২ য় কেস (যখন ক্যোয়ারসেট ইতিমধ্যে আনা হয়েছে):

    for obj in queryset: # iteration fetches the data
        len(queryset) # using already cached data - O(1) no extra cost
        queryset.count() # using cache - O(1) no extra db query
    
    len(queryset) # the same O(1)
    queryset.count() # the same: no query, O(1)
    

আপনি একবার "হুডের নীচে" এক নজরে নিলে সবকিছু পরিষ্কার হয়ে যাবে:

class QuerySet(object):

    def __init__(self, model=None, query=None, using=None, hints=None):
        # (...)
        self._result_cache = None

    def __len__(self):
        self._fetch_all()
        return len(self._result_cache)

    def _fetch_all(self):
        if self._result_cache is None:
            self._result_cache = list(self.iterator())
        if self._prefetch_related_lookups and not self._prefetch_done:
            self._prefetch_related_objects()

    def count(self):
        if self._result_cache is not None:
            return len(self._result_cache)

        return self.query.get_count(using=self.db)

জাজানো ডক্সে ভাল রেফারেন্স:


4
উজ্জ্বল উত্তর, QuerySetপ্রাসঙ্গিকভাবে বাস্তবায়ন পোস্ট করার জন্য +1 ।
নেহেম

4
বেশ আক্ষরিক অর্থে সঠিক উত্তর। কী ব্যবহার করবেন এবং আরও গুরুত্বপূর্ণ কারণ কেন ব্যবহারের তা ব্যাখ্যা করছেন।
টম পেগলার

28

আমি মনে করি len(qs)যে ফলাফলগুলি আপনাকে পুনরাবৃত্তি করতে হবে তাই এখানে ব্যবহার আরও বোধগম্য। qs.count()আপনি যা করতে চান তার সবগুলিই কাউন্টটি মুদ্রণ করুন এবং ফলাফলগুলির উপরে পুনরাবৃত্তি না করা যদি এটি একটি ভাল বিকল্প।

len(qs)ডাটাবেস হিট করবে select * from tableযেখানে qs.count()ডিবি দিয়ে আঘাত করবে select count(*) from table

এছাড়াও qs.count()প্রত্যাবর্তন পূর্ণসংখ্যা দেবে এবং আপনি এটির উপরে পুনরাবৃত্তি করতে পারবেন না


3

পরীক্ষার পরিমাপ পছন্দ করে এমন লোকদের জন্য (পোস্টারস্কেল):

যদি আমাদের কাছে একটি সহজ ব্যক্তি মডেল এবং এর 1000 টি উদাহরণ রয়েছে:

class Person(models.Model):
    name = models.CharField(max_length=100)
    age = models.SmallIntegerField()

    def __str__(self):
        return self.name

গড় ক্ষেত্রে এটি দেয়:

In [1]: persons = Person.objects.all()

In [2]: %timeit len(persons)                                                                                                                                                          
325 ns ± 3.09 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)

In [3]: %timeit persons.count()                                                                                                                                                       
170 ns ± 0.572 ns per loop (mean ± std. dev. of 7 runs, 10000000 loops each)

সুতরাং আপনি কীভাবে এই বিশেষ পরীক্ষার ক্ষেত্রে count()প্রায় 2x দ্রুত দেখতে পাচ্ছেন len()


0

অন্যরা ইতিমধ্যে কী জবাব দিয়েছে তা সংক্ষেপে:

  • len() সমস্ত রেকর্ড আনবে এবং সেগুলি পুনরাবৃত্তি করবে।
  • count() একটি এসকিউএল COUNT অপারেশন সম্পাদন করবে (বড় ক্যোয়ারসেটের সাথে ডিল করার সময় অনেক দ্রুত)।

এটিও সত্য যে যদি এই অপারেশনের পরে, পুরো ক্যোয়ারসেটটি পুনরাবৃত্তি করা হবে, তবে সামগ্রিকভাবে এটি ব্যবহারে কিছুটা দক্ষ হতে পারে len()

যাহোক

কিছু ক্ষেত্রে, উদাহরণস্বরূপ যখন মেমরির সীমাবদ্ধতা থাকে, তখন রেকর্ডগুলির উপর সঞ্চালিত ক্রিয়াকলাপটি বিভক্ত করা সুবিধাজনক (যখন সম্ভব হয়) হতে পারে। এটি জাঙ্গো পৃষ্ঠাগুলি ব্যবহার করে অর্জন করা যেতে পারে ।

তারপরে, ব্যবহার count()করা পছন্দ হবে এবং আপনি একবারে পুরো ক্যোরিসেটটি আনতে পারবেন না।

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.