Django queryset iterator() 没有按预期工作

Posted

技术标签:

【中文标题】Django queryset iterator() 没有按预期工作【英文标题】:Django queryset iterator() doesn't work as expected 【发布时间】:2019-05-25 16:43:14 【问题描述】:

我已经基于 Django 文档测试了queryset.iterator()

Oracle 和 PostgreSQL 使用服务器端游标从数据库中流式传输结果,而无需将整个结果集加载到内存中。

对于服务器端游标,chunk_size 参数指定要在数据库驱动程序级别缓存的结果数。获取更大的块会减少数据库驱动程序和数据库之间的往返次数,但会消耗内存。

在 PostgreSQL 上,仅当 DISABLE_SERVER_SIDE_CURSORS 设置为 False 时才会使用服务器端游标。

print(settings.DATABASES['default']['ENGINE']) # postgresql

class TestModel(Model):
    age = IntegerField(default=1)

# Insert 10 rows
for i in range(10):
    TestModel().save()

settings.DEBUG = True
l = logging.getLogger('django.db.backends')
l.setLevel(logging.DEBUG)
l.addHandler(logging.StreamHandler())   
# From now, every queries emitted by Django will be printed.    

print(settings.DISABLE_SERVER_SIDE_CURSORS) # False

for i in TestModel.objects.all().iterator(chunk_size=2):
    print(i.age)

(0.001) DECLARE "_django_curs_4369655232_3" NO SCROLL CURSOR WITH HOLD FOR SELECT "testmodel"."age" FROM "testmodel"; args=()

由于chunk_size=2,我预计上面的代码每2行会访问数据库5次(总行数为10)。

但是,它似乎只发出一个查询(在打印查询之上)。

我对@9​​87654324@有误解吗?

【问题讨论】:

【参考方案1】:

你已经正确理解了queryset.iterator()的目的。

在这种情况下(PostgreSQL),Django 声明了一个游标(使用 DECLARE 语句),它应该在迭代器中使用。

要从游标中获取数据,首先应该打开游标(使用OPEN 语句),然后获取数据(使用FETCH 语句)。

您的日志记录似乎没有捕捉到迭代器内部发生的任何这些语句,要确认这一点,您可以在 PostgreSQL 端设置日志记录:)。

【讨论】:

以上是关于Django queryset iterator() 没有按预期工作的主要内容,如果未能解决你的问题,请参考以下文章

Django框架 之 querySet详解

Django 不返回QuerySets的API

queryset优化 。。。。。exists()与iterator()方法

Django学习之model进阶

Django-model进阶

Django QuerySet