On Fri, Jul 19, 2019, at 4:40 AM, yoch melka wrote: > Thank you for your help. > > I'd be happy to submit a PR (I've already tried to fix this by myself), but > the code is a little hard to master.
I'm glad you tried. The feature is in review at https://gerrit.sqlalchemy.org/#/c/1368/. Of particular importance is that it has a new "degrade" step in the very unlikely case that the foreign key attributes on the parent object are unloaded; rather than emitting a separate query for those, it goes back to the JOIN. I would encourage you, if possible, to download the patch for the 1.3 series from https://gerrit.sqlalchemy.org/#/c/sqlalchemy/sqlalchemy/+/1369/ and ensure it works and performs as expected for your use case, though a SQLAlchemy release is now overdue and this may go out quickly. > > Le vendredi 19 juillet 2019 01:24:03 UTC+3, Mike Bayer a écrit : >> >> >> On Thu, Jul 18, 2019, at 5:02 PM, yoch melka wrote: >>> Hi, >>> >>> According to the documentation >>> <https://docs.sqlalchemy.org/en/13/orm/loading_relationships.html#select-in-loading>, >>> from 1.3 "selectin loading can omit the JOIN for a simple one-to-many >>> collection" in case if the PK is known by the primary request. >>> >>> But in the opposite case that we know the FK, it's not exploited by >>> Sqlalchemy to produce more effective queries. >>> >>> Example: >>> >>> from sqlalchemy import Table, Column, Integer, ForeignKey, create_engine >>> from sqlalchemy.orm import relationship, sessionmaker, selectinload >>> from sqlalchemy.ext.declarative import declarative_base >>> >>> >>> Base = declarative_base() >>> >>> class Parent(Base): >>> __tablename__ = 'parent' >>> id = Column(Integer, primary_key=True) >>> child_id = Column(Integer, ForeignKey('child.id')) >>> child = relationship("Child") >>> >>> class Child(Base): >>> __tablename__ = 'child' >>> id = Column(Integer, primary_key=True) >>> >>> >>> engine = create_engine('sqlite://') >>> engine.echo = True >>> >>> Base.metadata.create_all(engine) >>> >>> Session = sessionmaker(bind=engine) >>> db=Session() >>> >>> # create some data >>> c1 = Child() >>> db.add(c1) >>> for n in range(10): >>> p = Parent(child=c1) >>> db.add(p) >>> db.commit() >>> >>> >>> l = db.query(Parent).options(selectinload(Parent.child)).all() >>> >>> The last instruction above will produce the following two SQL queries : >>> >>> SELECT parent.id AS parent_id, parent.child_id AS parent_child_id >>> FROM parent >>> >>> SELECT parent_1.id AS parent_1_id, child.id AS child_id >>> FROM parent AS parent_1 JOIN child ON child.id = parent_1.child_id >>> WHERE parent_1.id IN (1, 2, 3, 4, 5, 6, 7, 8, 9, 10) >>> ORDER BY parent_1.id >>> >>> But in fact, the ORM have enough information to made the second query >>> simply: >>> >>> SELECT child.id AS child_id >>> FROM child >>> WHERE id IN (1) >>> >>> because we know that all child_id we have in parents are 1. >>> >>> Is it can be improved ? >> >> >> certainly, do you have resources to work on a pull request? it would require >> a new method like _init_for_omit_join() [1] as well as an alternate strategy >> inside of _load_for_path() [2] which loads the related objects, and matches >> them to the parents, in a different way. >> >> You can get almost the same effect right now, with a little bit less >> internal effiency, to just load the Child objects directly in a list, then >> access the attribute upon each Parent, which loads them from the identity >> map: >> >> l = db.query(Parent).all() >> c = db.query(Child).filter(Child.id.in_([p.id for p in l])).all() >> for p in l: >> p.child # no query is emitted >> >> >> a PR for this feature could be informed by a similar strategy, though the >> "p.child" part should likely use a faster route to populating the attribute >> directly the way the current strategy does. >> >> >> [1] >> https://github.com/sqlalchemy/sqlalchemy/blob/master/lib/sqlalchemy/orm/strategies.py#L2097 >> [2] >> https://github.com/sqlalchemy/sqlalchemy/blob/master/lib/sqlalchemy/orm/strategies.py#L2196 >> >> >>> >>> >>> -- >>> SQLAlchemy - >>> The Python SQL Toolkit and Object Relational Mapper >>> >>> http://www.sqlalchemy.org/ >>> >>> To post example code, please provide an MCVE: Minimal, Complete, and >>> Verifiable Example. See http://stackoverflow.com/help/mcve for a full >>> description. >>> --- >>> You received this message because you are subscribed to the Google Groups >>> "sqlalchemy" group. >>> To unsubscribe from this group and stop receiving emails from it, send an >>> email to sqlal...@googlegroups.com. >>> To post to this group, send email to sqlal...@googlegroups.com. >>> Visit this group at https://groups.google.com/group/sqlalchemy. >>> To view this discussion on the web visit >>> https://groups.google.com/d/msgid/sqlalchemy/b199fba3-8aaf-4e23-b406-865c3e57986c%40googlegroups.com >>> >>> <https://groups.google.com/d/msgid/sqlalchemy/b199fba3-8aaf-4e23-b406-865c3e57986c%40googlegroups.com?utm_medium=email&utm_source=footer>. >>> For more options, visit https://groups.google.com/d/optout. >> > > -- > SQLAlchemy - > The Python SQL Toolkit and Object Relational Mapper > > http://www.sqlalchemy.org/ > > To post example code, please provide an MCVE: Minimal, Complete, and > Verifiable Example. See http://stackoverflow.com/help/mcve for a full > description. > --- > You received this message because you are subscribed to the Google Groups > "sqlalchemy" group. > To unsubscribe from this group and stop receiving emails from it, send an > email to sqlalchemy+unsubscr...@googlegroups.com. > To post to this group, send email to sqlalchemy@googlegroups.com. > Visit this group at https://groups.google.com/group/sqlalchemy. > To view this discussion on the web visit > https://groups.google.com/d/msgid/sqlalchemy/efc5ccd1-e94a-4b13-909e-62063325f332%40googlegroups.com > > <https://groups.google.com/d/msgid/sqlalchemy/efc5ccd1-e94a-4b13-909e-62063325f332%40googlegroups.com?utm_medium=email&utm_source=footer>. > For more options, visit https://groups.google.com/d/optout. -- SQLAlchemy - The Python SQL Toolkit and Object Relational Mapper http://www.sqlalchemy.org/ To post example code, please provide an MCVE: Minimal, Complete, and Verifiable Example. See http://stackoverflow.com/help/mcve for a full description. --- You received this message because you are subscribed to the Google Groups "sqlalchemy" group. To unsubscribe from this group and stop receiving emails from it, send an email to sqlalchemy+unsubscr...@googlegroups.com. To post to this group, send email to sqlalchemy@googlegroups.com. Visit this group at https://groups.google.com/group/sqlalchemy. To view this discussion on the web visit https://groups.google.com/d/msgid/sqlalchemy/d864abc8-1b40-4b83-b479-e6eec626b8b3%40www.fastmail.com. For more options, visit https://groups.google.com/d/optout.