【问题标题】:Sqlalchemy eager loading of parent all properties in joined table inheritanceSqlalchemy 急切加载连接表继承中的父所有属性
【发布时间】:2014-07-23 11:19:01
【问题描述】:

我有以下问题:

我有一个具有连接表继承的类的层次结构:

class AdGroupModel(Base, AdwordsRequestMixin):
    __tablename__ = 'ad_groups'

    db_id = Column(BigInteger, primary_key=True)
    created_at = Column(DateTime(timezone=False), nullable=False, default=datetime.datetime.now())

    # ----RELATIONS-----
    # campaign MANY-to-ONE
    campaign_db_id = Column(BigInteger,
                            ForeignKey('campaigns.db_id', ondelete='CASCADE'),
                            nullable = True,
                            )
    # # ads ONE-to-MANY
    ads = relationship("AdModel",
                       backref="ad_group",
                       lazy="subquery",
                       passive_deletes=True,
                       single_parent=True,
                       cascade="all, delete, delete-orphan")
    # # # keywords ONE-to-MANY
    criteria = relationship("AdGroupCriterionModel",
                            backref="ad_group",
                            lazy="subquery",
                            passive_deletes=True,
                            single_parent=True,
                            cascade="all, delete, delete-orphan")


    # Joined Table Inheritance
    type = Column(Unicode(50))
    __mapper_args__ = {
        'polymorphic_identity': 'ad_group',
        'polymorphic_on': type
    }





class AdGroupCriterionModel(Base, AdGroupDependenceMixin):
    __tablename__ = 'ad_group_criterion'

    db_id = Column(BigInteger, primary_key=True)

    destination_url = Column(Unicode, nullable=True)
    status = Column(Enum("PAUSED", "ACTIVE", "DELETED",
                         name='criterion_status'), default="ACTIVE")



    # ----RELATIONS---
    # ad_group ONE-to-MANY
    ad_group_db_id = Column(BigInteger, ForeignKey('ad_groups.db_id',
                                                   ondelete='CASCADE'), nullable=True)

    # Joined Table Inheritance
    criterion_sub_type = Column(Unicode(50))
    __mapper_args__ = {
        'polymorphic_on': criterion_sub_type
    }



class AdGroupKeywordModel(AdGroupCriterionModel):
    __tablename__ = 'ad_group_keyword'
    __mapper_args__ = {'polymorphic_identity': 'Keyword'}
    db_id = Column(Integer, ForeignKey('ad_group_criterion.db_id'), primary_key=True)

    text = Column(Unicode, nullable=False)


class AdGroupDependenceMixin(object):
    _aggad_id = Column(BigInteger, nullable=True)
    _agname = Column(Unicode, nullable=True)

    @hybrid_property
    def ad_group_GAD_id(self):
        if self.ad_group is None:
            res = self._aggad_id
        else:
            res = self.ad_group.GAD_id
        return res

    @ad_group_GAD_id.setter
    def ad_group_GAD_id(self, value):
        self._aggad_id = value
        if value is not None:
            self.ad_group = None

    @ad_group_GAD_id.expression
    def ad_group_GAD_id(cls):
        what = case([( cls._aggad_id != None,  cls._aggad_id)], else_=AdGroupModel.GAD_id)
        return what.label('adgroupgadid_expression')

    @hybrid_property
    def ad_group_name(self):
        if self.ad_group is None:
            return self._agname
        else:
            return self.ad_group.name

    @ad_group_name.setter
    def ad_group_name(self, value):
        self._agname = value
        if value is not None:
            self.campaign = None

    @ad_group_name.expression
    def ad_group_name(cls):
        what = case([( cls._agname != None,  cls._agname)], else_=AdGroupModel.name)
        return what.label('adgroupname_expression')




And I load the Keywords objects from the database with the following query:

    all_objects1 = self.database.session.query(AdGroupKeywordModel).join(AdGroupModel)\
        .options(subqueryload('ad_group'))\
        .filter(AdGroupModel.GAD_id!=None)\
        .limit(self.options.limit).all()

返回AdGroupKeywordModel类型的对象。

不幸的是,每次我尝试访问父表 (AdGroupCriterionModel) 中 AdGroupKeywordModel 的属性时,都会发出这种类型的查询:

sqlalchemy.engine.base.Engine 
    SELECT ad_group_criterion.destination_url AS ad_group_criterion_destination_url, ad_group_criterion.status AS ad_group_criterion_status, ad_group_criterion.ad_group_db_id AS ad_group_criterion_ad_group_db_id, ad_group_criterion.criterion_sub_type AS ad_group_criterion_criterion_sub_type, ad_group_keyword.text AS ad_group_keyword_text
    FROM ad_group_criterion JOIN ad_group_keyword ON ad_group_criterion.db_id = ad_group_keyword.db_id 

这会严重影响性能。

我想要的是与父级(以及关系中定义的其他类)相关的类AdGroupKeywordModel 的所有属性与初始查询一起加载并缓存以供进一步使用。这样当我访问它们时,我不会从进一步的 sqlstatements 中获得任何开销。

似乎只为关系定义了预加载,而不为层次结构定义。是否有可能在 sqlalchemy 中对层次结构也有这种行为?

谢谢

【问题讨论】:

  • 看来您至少应该为您正在谈论的所有内容提供代码。你的关系和 subqueryload('ad_group') 引用的东西在你的代码中都不可见,所以没人知道。
  • @knitti 抱歉,我不想让代码过于复杂,我希望现在更清楚我想要做什么谢谢。

标签: sqlalchemy


【解决方案1】:

我看到的是:只有AdGroupModellazy= 定义(这是定义关系急切加载的关键字)有关系,并且查询只有subqueryload('ad_group')

ad_groupAdGroupModelAdGroupKeywordModel 接触的唯一点是在 AdGroupModel.criteria 中,它的后向引用为 AdGroupCriterionModel.ad_group。我不熟悉subqueryload 语法,但如果我想预先加载AdGroupCriterionModel.ad_group,我会这样定义criteria

criteria = relationship(
    "AdGroupCriterionModel", backref=backref("ad_group", lazy="subquery"),
    lazy="subquery", passive_deletes=True, single_parent=True,
    cascade="all, delete, delete-orphan")

关键在于为backref定义正确的lazy

【讨论】:

  • 感谢这个工作,似乎对于 sqlalchemy,您需要将关系指定为双方的子查询
  • 谢谢你!我没有明确意识到这种方式不对称的急切加载定义是可能的。现在我已经能够稍微优化我的一些模型了。
猜你喜欢
  • 2010-11-19
  • 1970-01-01
  • 1970-01-01
  • 2018-05-15
  • 1970-01-01
  • 2013-07-25
  • 1970-01-01
  • 2015-03-12
  • 1970-01-01
相关资源
最近更新 更多