Sqlalchemy – разница между запросом и query.all в циклах for
-
21-08-2019 - |
Вопрос
Я хотел бы спросить, в чем разница между
for row in session.Query(Model1):
pass
и
for row in session.Query(Model1).all():
pass
является ли первый каким-то образом итератором, бомбардирующим вашу БД отдельными запросами, а второй «нетерпеливо» запрашивает все это в виде списка (например, range(x) vs xrange(x))?
Решение
Нет, разницы в трафике БД нет.Разница только в том, что for row in session.Query(Model1)
работает ли ORM с каждой строкой, когда он собирается ее вам передать, в то время как for row in session.Query(Model1).all()
работает ли ORM со всеми строками, прежде чем начать их вам выдавать.
Обратите внимание, что q.all()
это просто сахар для list(q)
, т.е.собираем все, что выдает генератор, в список.Здесь исходный код для этого в Query
класс (найти 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()
пробираясь через это.
Практическая разница состоит в том, что первое может начнет предоставлять вам строки, как только их данные поступят, «передавая» вам набор результатов БД с меньшим использованием памяти и задержкой.Я не могу с уверенностью утверждать, что все текущие реализации движка делают это (надеюсь, что так!).В любом случае последняя версия без веской причины препятствует этой эффективности.