限制* Large * Django QuerySet中的内存使用

发布于 2021-01-29 17:05:22

我有一项任务,需要每隔一段时间(一天一次,每周一次,等等)在数据库的“大多数”对象上运行。基本上,这意味着我有一些查询,看起来像是在自己的线程中运行。

for model_instance in SomeModel.objects.all():
    do_something(model_instance)

(请注意,它实际上是一个filter()而不是all(),但是我仍然选择了 很多 对象。)

我遇到的问题是,运行了一段时间后,线程被我的托管提供程序杀死了,因为我使用了太多的内存。我 假设
所有这些内存使用都在发生,因为即使QuerySet我的查询返回的对象最初具有很小的内存占用空间,但随着QuerySet对象在每次model_instance迭代它们时都缓存每个对象,它最终会增长。

我的问题是,“SomeModel以一种内存有效的方式遍历数据库中几乎每个数据库的最佳方法是什么?”
还是我的问题是“如何从Django查询集中’取消缓存’模型实例?”

编辑:我实际上是在使用queryset的结果来构建一系列新对象。 因此,我根本不会更新所有查询的对象。

关注者
0
被浏览
52
1 个回答
  • 面试哥
    面试哥 2021-01-29
    为面试而生,有面试问题,就找面试哥。

    因此,我实际上最终要做的是构建可以“包装”
    QuerySet的内容。它可以通过使用slice语法对QuerySet进行some_queryset[15:45]深拷贝来工作(例如,),但随后会对原始QuerySet进行另一次深拷贝。当切片已完全迭代通过时。这意味着仅在“此”特定切片中返回的对象集存储在内存中。

    class MemorySavingQuerysetIterator(object):
    
        def __init__(self,queryset,max_obj_num=1000):
            self._base_queryset = queryset
            self._generator = self._setup()
            self.max_obj_num = max_obj_num
    
        def _setup(self):
            for i in xrange(0,self._base_queryset.count(),self.max_obj_num):
                # By making a copy of of the queryset and using that to actually access
                # the objects we ensure that there are only `max_obj_num` objects in
                # memory at any given time
                smaller_queryset = copy.deepcopy(self._base_queryset)[i:i+self.max_obj_num]
                logger.debug('Grabbing next %s objects from DB' % self.max_obj_num)
                for obj in smaller_queryset.iterator():
                    yield obj
    
        def __iter__(self):
            return self
    
        def next(self):
            return self._generator.next()
    

    所以代替…

    for obj in SomeObject.objects.filter(foo='bar'): <-- Something that returns *a lot* of Objects
        do_something(obj);
    

    你会做…

    for obj in MemorySavingQuerysetIterator(in SomeObject.objects.filter(foo='bar')):
        do_something(obj);
    

    请注意,这样做的目的是为了 节省 Python解释 中的 内存 。它实质上是通过进行 更多的
    数据库查询来实现的。通常,人们正试图做与之完全相反的事情,即,在不考虑内存使用情况的情况下,尽可能减少数据库查询。希望有人会发现这很有用。



知识点
面圈网VIP题库

面圈网VIP题库全新上线,海量真题题库资源。 90大类考试,超10万份考试真题开放下载啦

去下载看看