我正与同事讨论通过Django ORM迭代大表。到目前为止,我一直在使用queryset_iterator的实现,如下所示:
def queryset_iterator(queryset, chunksize=1000):
'''''
Iterate over a Django Queryset ordered by the primary key
This method loads a maximum of chunksize (default: 1000) rows in it's
memory at the same time while django normally would load all rows in it's
memory. Using the iterator() method only causes it to not preload all the
classes.
Note that the implementation of the iterator does not support ordered query sets.
'''
pk = 0
last_pk = queryset.order_by('-pk')[0].pk
queryset = queryset.order_by('pk')
while pk < last_pk:
for row in queryset.filter(pk__gt=pk)[:chunksize]:
pk = row.pk
yield row
gc.collect()
我的同事建议使用Django's Paginator并将查询集传递给它。似乎类似的工作会完成,我能找到的唯一区别是Paginator不会进行任何垃圾收集调用。
有人能说清楚两者之间的区别吗?有没有?
答案 0 :(得分:2)
这里的实施与Paginator所做的完全不同;几乎没有任何相似之处。
您的类遍历整个查询集,一次请求chunksize
项,每个块都是一个单独的查询。它只能用于非有序查询,因为它自己执行order_by调用。
Paginator没有这样做。它不是用于迭代整个查询集,而是用于从完整的qs返回单个页面,它使用切片运算符(映射到LIMIT / OFFSET)进行单个查询。
另外,我不确定你认为gc.collect
会在这里做什么。垃圾收集器是主内存管理系统的附加组件,它是引用计数。它仅用于清理循环引用,并且没有理由相信会在此处创建。