sqlalchemy查询相关表:要加入还是不加入(然后循环)?

时间:2018-08-21 23:18:17

标签: python sqlalchemy

目标:

  1. 从一个表中检索查询结果列表(称为“组”)。
  2. 从相关表中检索结果列表(称为“项目”)。步骤1中每个结果的一个结果列表。
  3. 在一个既包含“组”数据又包含所有相关“项目”数据列表的元组中,将步骤2的“项目”列表与步骤1的相应“组”结果结合起来。

问题:

将上述第1步和第2步与一个联接查询结合起来,然后循环遍历以按组筛选和汇总结果是否更有效?还是更有效地查询步骤1的结果,然后循环查询步骤2的结果并汇总结果?

接下来是每种方法的示例,希望还有其他更好的方法...

带循环方法(带连接)的单个查询:

# query all "groups" in "category1" and all related "items"
results = session.query(Group.id, Group.name, Item.id, Item.name).\
    outerjoin(Item, Group.items).\
    filter(Group.category == 'category1').\
    order_by(Group.id).\
    all()

groups = list()
group_ids = set(results[0][0])
current_group = results[0][:2]
current_group_items = list()

for result in results:
    # for each result, combine "group" with all related "items"
    if result[0] in group_ids:
        current_group_items.append(result[2:])
    else:
        groups.append(current_group + (current_group_items,))
        group_ids.add(result[0])
        current_group = result[:2]
        current_group_items = [result[2:]]

使用循环方法的多个查询(无联接):

# query all "groups" in "category1"
groups = session.query(Group.id, Group.name).\
    filter(Group.category == 'category1').\
    all()

results = []

for group in groups:
    # for each "group", query all related "items"
    items = session.query(Item.id, Item.name).\
        filter(Item.group_id == group[0]).\
        all()
    # append list of related "items" to "group" result
    results.append(group + (items,))

示例架构供参考:

from sqlalchemy import Column, Integer, String, ForeignKey
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import relationship


Base = declarative_base()

class Group(Base):
    __tablename__ = 'groups'

    id = Column(Integer, primary_key=True)
    name = Column(String, nullable=False, index=True)
    category = Column(String, nullable=False, index=True)
    items = relationship('Sub', back_populates='group', cascade='all')

class Item(Base):
    __tablename__ = 'items'

    id = Column(Integer, primary_key=True)
    name = Column(String, nullable=False, index=True)
    group_id = Column(Integer, ForeignKey('groups.id'), nullable=False)
    group = relationship('Group', back_populates='items')

1 个答案:

答案 0 :(得分:1)

还有第三个使用联接的选项:让SQLAlchemy渴望加载项目并为您处理分组,因为您已经在GroupItem之间建立了联系:

from sqlalchemy.orm import joinedload

groups = session.query(Group).\
    options(joinedload(Group.items)).\
    filter(Group.category == '...').\
    all()

然后您将使用Group.items集合访问组中的项目。

一般来讲,joinedload的性能比第二个示例中的“ 1 + N”查询方法更好,这是因为执行查询会涉及到延迟。当然,这是一种概括,有时甚至可以赢得单独的查询,但是即使在那种情况下,您仍然可以使用这些关系-默认的关系加载策略为'select'