我正在将Django 1.11与MySQL配合使用。短期内升级到2是不可行的,因此对于我眼前的问题也不是可接受的解决方案,但是有关Django 2的答案可能会帮助其他人,所以可以随时发布它们。
我需要对表中的所有行执行数据迁移。少于40000行,但它们很大-两列是〜15KB的JSON,在加载模型时会对其进行解析。 (这些是我在数据迁移中需要使用的行,因此我无法defer它们行)
为了避免将所有对象同时加载到内存中,我认为我会使用queryset.iterator,它一次只能解析100行。如果我所做的只是读取结果,则此方法很好,但是如果我执行另一个查询(例如,对save
个对象进行查询),则一旦达到当前100个结果块的末尾,下一个100个块结果无法获取,并且迭代器完成。
好像fetchmany从中获取行的结果集丢失了。
为了说明使用./manage.py shell
的情况
(假设存在40000个具有顺序ID的MyModel)
iterator = app.models.MyModel.objects.iterator()
for obj in iterator:
print(obj.id)
上面的代码会按预期打印ID 1到40000。
iterator = app.models.MyModel.objects.iterator()
for obj in iterator:
print(obj.id)
obj.save()
以上仅显示ID 1到100
iterator = app.models.MyModel.objects.iterator()
for obj in iterator:
print(obj.id)
if obj.id == 101:
obj.save()
以上仅显示ID 1至200
将obj.save
替换为对数据库进行查询的其他任何内容(例如app.models.OtherModel.objects.first()
)。
使用queryset迭代器时是否根本无法进行其他查询?还有另一种方法可以实现相同的目的吗?
谢谢
答案 0 :(得分:0)
如@dirkgroten所建议,Paginator是迭代器的替代方案,它在内存使用方面可能是更好的解决方案,因为它对查询集使用切片,并添加了OFFSET和LIMIT子句以仅检索部分完整结果集。>
但是,较高的OFFSET值会导致MySQL性能下降:https://www.eversql.com/faster-pagination-in-mysql-why-order-by-with-limit-and-offset-is-slow/
因此,在索引列上进行搜索可能是一个更好的选择:
chunk_size = 100
seek_id = 0
next_seek_id = -1
while seek_id != next_seek_id:
seek_id = next_seek_id
for obj in app.models.MyModel.objects.filter(id__gt=seek_id)[:chunk_size]:
next_seek_id = obj.id
# do your thing
此外,如果您的数据使得执行查询并不昂贵,但是实例化模型实例非常昂贵,则迭代器具有执行单个数据库查询的潜在优势。希望其他答案能够阐明将queryset.iterator与其他查询一起使用。