擅长:python、mysql、java
<p>大多数DBAPI实现在获取行时对行进行完全缓冲,因此通常在SQLAlchemy ORM获得一个结果之前,整个结果集就在内存中。</p>
<p>但是,<code>Query</code>的工作方式是,在返回对象之前,默认情况下它会完全加载给定的结果集。这里的基本原理涉及的查询不仅仅是简单的SELECT语句。例如,在与可能在一个结果集中多次返回同一对象标识的其他表的联接(与紧急加载相同)中,需要将完整的行集合放在内存中,以便可以返回正确的结果,否则可能只填充部分集合。</p>
<p>因此<code>Query</code>提供了一个选项,可以通过<a href="http://www.sqlalchemy.org/docs/orm/query.html?highlight=yield_per#sqlalchemy.orm.query.Query.yield_per" rel="nofollow noreferrer">^{<cd3>}</a>更改此行为。此调用将导致<code>Query</code>成批生成行,并在其中指定批大小。正如docs所说,只有在您没有进行任何类型的集合加载的情况下,这才是合适的,所以基本上是在您真正知道自己在做什么的情况下。另外,如果底层的DBAPI预缓冲了行,那么仍然会有内存开销,因此该方法的伸缩性比不使用它稍微好一些。</p>
<p>我几乎从不使用<code>yield_per()</code>;相反,我使用的是您建议的使用窗口函数的更好版本的极限方法。LIMIT和OFFSET有一个很大的问题,即非常大的OFFSET值会导致查询变得越来越慢,因为OFFSET为N会导致查询在N行中分页,这就像每次读取越来越多的行时,执行相同的查询五十次而不是一次。使用窗口函数方法,我预先获取一组“窗口”值,这些值引用要选择的表块。然后,我发出单独的SELECT语句,每次都从这些窗口中提取一个。</p>
<p>窗口函数方法是<a href="http://www.sqlalchemy.org/trac/wiki/UsageRecipes/WindowedRangeQuery" rel="nofollow noreferrer">on the wiki</a>,我使用它非常成功。</p>
<p>另请注意:并非所有数据库都支持窗口函数;您需要Postgresql、Oracle或SQL Server。IMHO至少使用Postgresql是绝对值得的-如果您使用的是关系数据库,那么您最好使用最好的。</p>