我想问一下
之间的区别for row in session.Query(Model1):
pass
和
for row in session.Query(Model1).all():
pass
是第一个以某种方式用单个查询轰炸你的数据库的迭代器,后者“急切地”将整个事件作为一个列表查询(比如range(x)vs xrange(x))?
答案 0 :(得分:87)
不,数据库流量没有差异。不同之处在于for row in session.Query(Model1)
ORM在每一行即将提供给你的时候都会工作,而for row in session.Query(Model1).all()
在开始向你提供ORM之前对所有行都有效。< / p>
请注意q.all()
只是list(q)
的糖,即将生成器产生的所有内容收集到列表中。以下是Query
类中source code的{{3}}(在链接源中查找def all
):
def all(self):
"""Return the results represented by this ``Query`` as a list.
This results in an execution of the underlying query.
"""
return list(self)
...其中self
,查询对象,是一个可迭代的,即具有__iter__
方法。
从逻辑上讲,这两种方式在数据库流量方面完全相同;最终都调用query.__iter__()
来获取行迭代器,并next()
通过它。
实际的不同之处在于前者可以在数据到达后立即开始为您提供行,将数据库结果集“流式传输”给您,减少内存使用和延迟。我无法确定所有当前的引擎实现都是这样做的(我希望他们这样做!)。在任何情况下,后一版本都没有充分的理由阻止了这种效率。
答案 1 :(得分:3)
实际上,接受的响应不是真的(或者至少不再是真的),特别是以下陈述是错误的:
(1)的区别仅在于session.Query(Model1).all()中的行。Query(Model1)在将要提供给您的行上进行ORM工作,而session.Query(Model1).all( )在开始提供给您之前,ORM是否在所有行上都起作用。
无论选择使用2个选项中的哪一个,SQLAlchemy始终将ORM映射所有行。可以在these lines中的源代码中看到; loading.instances
方法确实将返回一个生成器,但是返回一个已经映射的ORM实例;您可以在实际的generator looping code中确认这一点:
for row in rows: # ``rows`` here are already ORM mapped rows
yield row
因此,在生成器的第一次运行完成并产生一个实例时,所有实例都已进行ORM映射。 (以下示例(1))
(2)实际的区别是,前者可以在数据到达后立即开始为您提供行,从而将DB结果集“流式传输”给您,从而减少了内存使用和延迟。
如上所述,这也是错误的,因为all data retrieved from the DB将在完成任何屈服之前进行处理/映射。
这些评论也具有误导性。具体来说:
数据库命中可能是相同的,但是请记住,所有操作都会将整个结果集加载到内存中。这可能是千兆字节的数据
无论是否使用.all()
,都会加载整个结果集。在this line中清晰可见。这也非常容易测试/验证。
我从陈述的2个选项中看到的唯一区别是,使用.all
会在生成器首先被迭代/耗尽时在结果中循环两次(如果要处理所有实例/行)。通过调用list(self)
将其转换为列表。
由于SQLAlchemy代码不容易理解,因此我写了一个简短的代码段来举例说明所有这一切:
class Query:
def all(self):
return list(self)
def instances(self, rows_to_fetch=5):
"""ORM instance generator"""
mapped_rows = []
for i in range(rows_to_fetch):
# ORM mapping work here as in lines 81-88 from loading.instances
mapped_rows.append(i)
print("orm work finished for all rows")
for row in mapped_rows: # same as ``yield from mapped_rows``
print("yield row")
yield row
def __iter__(self):
return self.instances()
query = Query()
print("(1) Generator scenario:")
print("First item of generator: ", next(iter(query)))
print("\n(2) List scenario:")
print("First item of list: ", query.all()[0])
"""
RESULTS:
--------
(1) Generator scenario:
orm work finished for all rows
yield row
First item of generator: 0
(2) List scenario:
orm work finished for all rows
yield row
yield row
yield row
yield row
yield row
First item of list: 0
"""
为了在处理大型结果集时拥有更好的控制,例如,必须使用类似yield_per的方法,但这仍然不是一个一例的场景,而是分批执行ORM映射。实例。
值得一提的是{em {em} ,并且很容易被忽略(因此写了这个答案),指向迈克尔·拜耳的only comment。 / p>