访问 author.books 的那一刻到底发生了什么?各种 lazy 策略发多少条 SQL?什么时候该用 eager loading?这篇用 SQL 事件把每种策略发出的语句一条一条数出来。
取出 1 个 Author:1 条 SQL 第一次访问 a.books:新增 1 条 → SELECT book.id, book.title, book.author_id FROM book WHERE ? = book.author_id 再访问 a.books 两次:新增 0 条 多对一 b.author:0 条(Author 1 已经在这个 session 的身份映射里,直接取不发 SQL) 清空 session 后再取 b.author:1 条 → SELECT author.id, author.name FROM author WHERE author.id = ?
lazy= SQL 条数 说明 select 11 SELECT author.id, author.name FROM author joined 1 SELECT author.id, author.name, book_1.id AS id_1, book_1.title, book_1.author_id… subquery 2 SELECT author.id, author.name FROM author selectin 2 SELECT author.id, author.name FROM author immediate 11 SELECT author.id, author.name FROM author raise 1 访问 books → InvalidRequestError: 'Author.books' is not available due to lazy='raise' (noload 触发的警告: SADeprecationWarning: The ``noload`` loader strategy is deprecated and will be rem…) noload 1 访问 books → 访问到 0 本
不加 options 11 条 SQL,遍历 books → 50 本 joinedload 1 条 SQL,遍历 books → 50 本 selectinload 2 条 SQL,遍历 books → 50 本 subqueryload 2 条 SQL,遍历 books → 50 本 raiseload 1 条 SQL,遍历 books → InvalidRequestError
对象 detached 后读 a.books → DetachedInstanceError raiseload 下读 a.books → InvalidRequestError | 'Author.books' is not available due to lazy='raise'
a.books 的类型: AppenderQuery 继续过滤 a.books.filter(...).all(): ['b0-1'] | 发了 1 条 连续 count() 两次:发了 2 条(不缓存)