SQLAlchemy中Select与Query API的区别及优劣势对比
SQLAlchemy Query API 与 Select API 差异解答
核心差异点
- 设计逻辑完全不同:1.x版本的
query()是ORM层专属的绑定式接口,查询构造和执行强绑定在Session实例上,你拿到session.query()返回的对象时,就已经和当前会话绑定了。2.0版本的select()是独立的语句构造对象,和执行层完全解耦——你可以在任何地方先拼好查询语句,需要执行的时候再丢给session.execute()跑,甚至可以把同一条Select语句传给Core层的连接、异步Session执行,不需要改写法。 - 返回值逻辑不同:旧
Query的first()、all()这类方法直接返回映射好的ORM实体,比如session.query(Users).first()直接给你Users类的实例。新Select API默认执行后返回的是Row元组对象,直接调用fetchone()拿到的是包裹了实体的元组,要拿到和旧API一致的单实体结果,可以调用scalar_one_or_none()方法,不用手动拆包。 - 功能覆盖范围不同:旧
Query只服务ORM场景,十几年迭代下来堆了很多专属的特殊逻辑,很多Core层支持的高级查询(比如复杂CTE、窗口函数、数据库方言专属语法)在Query上要么写起来非常绕,要么根本不支持。Select构造的语句是Core/ORM通用的,所有Core支持的语法都可以直接在ORM查询里用,没有功能壁垒。
关于性能优势
不存在感知明显的性能提升。两种写法最终生成的SQL语句、数据库执行计划、ORM层的实例映射逻辑在2.0正式版中是完全对齐的,没有本质区别。早期预览版里Select走新执行链路有几个百分点的微优化,但这个差距在常规业务查询里完全测不出来,远达不到“换API就显著提速”的程度。
官方主推Select API的原因
不是只为了打通ORM和Core的边界,本质是为了解决旧Query API攒了十几年的设计债:
- 旧Query因为和Session强绑定,迭代过程中加了大量隐式行为,比如多表Join时的实体覆盖、隐式自动刷新的触发逻辑不一致、隐式类型转换等,坑非常多,文档维护成本极高。
- 统一Select语法后,Core和ORM的学习路径完全合并,开发者不用再记两套查询API的规则,学会Select写法之后,写原生SQL拼接、ORM查询、异步查询都是同一套逻辑,学习成本低很多。
- 解耦的执行模式天然适配异步场景:旧Query的强绑定设计根本没法平滑适配异步IO,而Select+execute的模式可以无缝对接
AsyncSession,不用为异步场景单独开发一套查询接口。
补充说明:目前2.0正式版已经发布,Query API作为遗留接口会长期保留兼容,不会突然删除,但后续所有新功能都只会在Select API链路落地。新项目直接用Select风格即可,老项目不需要为了换API强行重构,原有Query写法可以正常运行。
相同查询逻辑的写法参考
查询Users表中匹配指定姓名、邮箱的用户,两种写法分别如下:
1.x 旧Query API写法:
session.query(Users).filter_by(name='name', email='mail@example.com').first()
2.0 新Select API等价写法:
from sqlalchemy import select query = select(Users).filter_by(name='name', email='mail@example.com') user = session.execute(query).scalar_one_or_none()
内容的提问来源于stack exchange,提问作者Shiladitya Bose
相关产品推荐
相关产品推荐

