SQLAlchemy进阶:Lazy Load 加载参数

参考:flask-sqlalchemy中的lazy的解释sql

SQLAlchemy的relationship( ..., lazy='??' )方法中的lazy参数一直是初学最容易困扰的地方。数据库

Lazy Load Methods是SQLAlchemy为多表关联而定义的一系列加载方法。为lazy参数选择什么值,决定了 SQLAlchemy 何时从数据库中加载数据。每种方法的对应着SQL语句中多表关联的一种写法,因此优缺点、效率高低各有不一样。flask

lazy参数的可选方法有:app

  • select - (默认) 后台会用select语句一次性加载全部数据,即访问到属性的时候,就会所有加载该属性的数据。
  • joined - 数据会被JOIN语句加载,即对关联的两个表进行join操做,从而获取到全部相关的对象。
  • subquery - 数据被用subquery子查询SQL语句加载
  • dynamic - 在访问属性的时候,并不在内存中加载数据,而是返回一个query对象, 须要执行相应方法才能够获取对象。适用于数据量大的时候。
  • immediate - items should be loaded as the parents are loaded, using a separate SELECT statement, or identity map fetch for simple many-to-one references.
  • noload - no loading should occur at any time. This is to support “write-only” attributes, or attributes which are populated in some manner specific to the application.
  • True - 即 'select'方法
  • False - 即 'joined'方法
  • None - 即'noload'方法

下面用SchoolStudents的实例来看各类方法的不一样。ide

假设定义两个ORM类:函数

class School(..):
    id = Column(..)
    students = relationship( 'Student', backref='school' )

class Student(..):
    id = Column(..)
    school_id = Column(.., ForeignKey('school.id') )

上例中咱们创建了一个普通的两表关联:students = relationship( 'Student', backref='school' )
默认状况下,参数lazy为select,咱们不写也能够)。
也就是说,若是定义lazy='select',那么当咱们要进行搜索引用时(假设表中已有数据):fetch

>>> school_01 = School.query.first()  # 随便获取一个数据库中已有的school
>>> school_01.students
[ <Student: u'test'>, <Student: u'test2'>, <Student: u'test3'> ]

能够看到,lazy='select'会简单直接的返回全部相关联的数据。
可是,若是数据量很是大:好比百万级,这种所有返回就不理智了,由于会大量侵占内存。
因此咱们能够选择lazy='dynamic',即只返回一个query查询对象,供你手动加条件查询,好比query.all()query.filter()等。code

假设咱们将以前的定义改成:students = db.relationship('Student', backref='_class', lazy="dynamic")。那么:orm

>>> school_01.students
<sqlalchemy.orm.dynamic.AppenderBaseQuery object at 0x7f007d2e8ed0>

>>> print( school_01.students )
SELECT students.id AS students_id, students.name AS students_name
FROM students, registrations
WHERE :param_1 = registrations.class_id AND students.id = registrations.student_id

>>> school_01.students.all()
[ <Student: u'test'>, <Student: u'test2'>, <Student: u'test3'> ]

能够看到, 执行school_01.students返回的只是一个query对象,甚至说只是返回了一条SQL
语句,就是没有具体数据。能够想像这个消耗的时间至关于0了。
而若是lazy=select 或者 joined均是直接返回结果。 对象

须要注意的是,
lazy="dynamic"只能够用在一对多和多对对关系中,不能够用在一对一和多对一中。

这样也合理:若是返回结果不多的话,就不必延迟加载数据了。

backref(..., lazy=...) 反向引用的lazy加载

直接给relationship(.., lazy='??'),只是给正向引用设置加载方法。
实际上反向引用也是能够设置lazy加载方法的。
作法就是:使用backref(..)函数:

students = relationship(..., lazy='..', backref=backref('Student, lazy='dynamic') )

能够看到,backref(..)函数返回的是一个backref参数专用的值,在这里面能够指定反向引用的加载方法。

相关文章
相关标签/搜索