Sqlalchemy - Различие между запросом и query.all в для циклов

Spark Sql уже имеют случайные функции, существует один блог .

Или для числа строк искра sql также имеет функцию row_number ().

68
задан Tom 3 July 2009 в 08:34
поделиться

2 ответа

Nope, there is no difference in DB traffic. The difference is just that for row in session.Query(Model1) does the ORM work on each row when it is about to give it to you, while for row in session.Query(Model1).all() does the ORM work on all rows, before starting to give them to you.

Note that q.all() is just sugar for list(q), i.e. collecting everything yielded by the generator into a list. Here is the source code for it, in the Query class (find def all in the linked source):

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)

... where self, the query object, is an iterable, i.e. has an __iter__ method.

So logically the two ways are exactly the same in terms of DB traffic; both end up calling query.__iter__() to get a row iterator, and next()ing their way through it.

The practical difference is that the former can start giving you rows as soon as their data has arrived, “streaming” the DB result set to you, with less memory use and latency. I can't state for sure that all the current engine implementations do that (I hope they do!). In any case the latter version prevents that efficiency, for no good reason.

94
ответ дан 24 November 2019 в 14:19
поделиться

На самом деле, принятый ответ не верен (или по крайней мере не больше, если когда-либо верный), конкретно следующие утверждения являются ложью:

(1) различие - просто это для строки на сессии. Запрос (Model1) делает работу ORM над каждой строкой, когда это собирается дать его Вам, в то время как для строки на сессии. Запрос (Model1).all () делает работу ORM над всеми строками, прежде, чем начать давать их Вам.

SQLAlchemy всегда будет ORM отображать все строки, неважно, которые из этих 2 опций Вы принимаете решение использовать. Это видно в их исходном коде в эти строки ; loading.instances метод действительно возвратит генератор, но один из уже отображенных экземпляров ORM; можно подтвердить это в на самом деле код цикличного выполнения генератора :

for row in rows: #  ``rows`` here are already ORM mapped rows
    yield row

Поэтому к тому времени, когда первый показ генератора закончился, и к экземпляру привели, все экземпляры были отображенным ORM. (Иллюстрируемый ниже (1))

(2) практическое различие - то, что первый может начать давать Вам строки, как только их данные прибыли, “streaming” набор результатов DB Вам, с меньшим количеством использования памяти и задержки.

Столь же замеченный объясненный выше этого также ложь как , все полученные данные от DB будут обработаны/отображены, прежде чем любое получение сделано.

комментарии также вводят в заблуждение. Конкретно:

хит базы данных может быть тем же, но примите во внимание, что все загрузят весь набор результатов в память. Это могло быть гигабайтами данных

, весь набор результатов будет загружен независимо от использования .all() или нет. Очевидно замеченный в эта строка . Это также очень легко тестировать/проверять.

единственная разница I видит от этих 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
"""

, Чтобы иметь любой более прекрасный контроль при обработке больших наборов результатов, нужно было бы использовать что-то как [1 110] yield_per, например, и все еще это не будет один за другим вариант развития событий, а скорее выполнение отображения ORM пакетами экземпляров.

Ценность для замечания только комментарий , который был действительно на точке и может быть легко пропущен (следовательно запись этого ответа) указывающий объяснение от Michael Bayer.

2
ответ дан 24 November 2019 в 14:19
поделиться
Другие вопросы по тегам:

Похожие вопросы: