Оптимизация SqlAlchemy для объектных моделей только для чтения

У меня есть сложная сеть объектов, порождаемых от sqlite базы данных с помощью sqlalchemy ORM отображения. У меня есть довольно многие глубоко вложенные:

for parent in owner.collection: 
    for child in parent.collection: 
        for foo in child.collection: 
            do lots of calcs with foo.property 

Мое профилирование показывает мне, что sqlalchemy инструментарий занимает много времени в этом варианте использования.

Вещь: Я никогда не изменяю объектную модель (отображенные свойства) во времени выполнения, поэтому как только они загружаются, мне не НУЖЕН инструментарий или действительно любой sqlalchemy наверху вообще. После большого исследования я думаю, что мне, возможно, придется клонировать 'чистый Python' набор объектов от моих уже загруженных 'оснащенных объектов', но это будет болью.

Производительность действительно крайне важна здесь (это - средство моделирования), поэтому возможно, пишущий те слои, поскольку C расширения с помощью sqlite API непосредственно было бы лучшим. Какие-либо мысли?

9
задан CarlS 23 February 2010 в 14:12
поделиться

3 ответа

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

Если вам нужен способ создания дешевых чистых клонов Python, поделитесь объектом dict с исходным объектом:

class CheapClone(object):
    def __init__(self, original):
        self.__dict__ = original.__dict__

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

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


Нашел быстрый и грязный способ, который, кажется, хоть немного работает с 0.5.8 и 0.6. Не тестировал его с помощью наследования или других функций, которые могут плохо взаимодействовать. Кроме того, это касается некоторых непубличных API, поэтому остерегайтесь поломки при изменении версии.

from sqlalchemy.orm.attributes import ClassManager, instrumentation_registry

class ReadonlyClassManager(ClassManager):
    """Enables configuring a mapper to return instances of uninstrumented 
    classes instead. To use add a readonly_type attribute referencing the
    desired class to use instead of the instrumented one."""
    def __init__(self, class_):
        ClassManager.__init__(self, class_)
        self.readonly_version = getattr(class_, 'readonly_type', None)
        if self.readonly_version:
            # default instantiation logic doesn't know to install finders
            # for our alternate class
            instrumentation_registry._dict_finders[self.readonly_version] = self.dict_getter()
            instrumentation_registry._state_finders[self.readonly_version] = self.state_getter()

    def new_instance(self, state=None):
        if self.readonly_version:
            instance = self.readonly_version.__new__(self.readonly_version)
            self.setup_instance(instance, state)
            return instance
        return ClassManager.new_instance(self, state)

Base = declarative_base()
Base.__sa_instrumentation_manager__ = ReadonlyClassManager

Пример использования:

class ReadonlyFoo(object):
    pass

class Foo(Base, ReadonlyFoo):
    __tablename__ = 'foo'
    id = Column(Integer, primary_key=True)
    name = Column(String(32))

    readonly_type = ReadonlyFoo

assert type(session.query(Foo).first()) is ReadonlyFoo
9
ответ дан 3 November 2019 в 03:46
поделиться

Попробуйте использовать одиночный запрос с JOINами вместо циклов python.

-1
ответ дан 3 November 2019 в 03:46
поделиться

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

0
ответ дан 3 November 2019 в 03:46
поделиться
Другие вопросы по тегам:

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