You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Flask API中SQLAlchemy ORM与原生SQL查询性能差异及优化咨询

问题解答:SQLAlchemy ORM比原生SQL更快的原因及优化方案

在Flask API的POST路由数据验证逻辑中,给目标模型新增列属性后API响应变慢,尝试用仅查询必要列的原生SQL优化,结果却比原SQLAlchemy ORM查询更慢。核心疑问有两个:

  1. 为何此处ORM查询更快?
  2. 如何通过SQLAlchemy ORM实现仅查询指定列的逻辑(或不新增列的关联查询)?

一、ORM查询更快的核心原因

对比两段代码的查询逻辑,性能差距主要来自以下几点:

  1. 查询复杂度差异
    ORM代码中BuyModel.query.filter_by(id=payload_buy_id).one()是单表查询,直接从buy表获取数据;而原生SQL做了三次表JOIN(buy→plan→brief),多表关联的IO开销远大于单表查询,自然更慢。从代码能看出,ORM中直接访问buy_record.brief_id、buy_record.client_id,说明你已经给BuyModel新增了这两个列,无需关联其他表即可获取数据。

  2. Session缓存与复用差异
    ORM大概率复用了Flask-SQLAlchemy提供的全局Session(比如db.session),SQLAlchemy会对Session内的查询结果做缓存;而原生SQL每次调用create_pg_session()新建Session,无法复用缓存,重复查询时会重复执行SQL语句。

  3. 查询执行的优化差异
    SQLAlchemy ORM会自动生成经过优化的SQL语句,且能利用数据库的主键索引(buy.id是主键,查询必然走索引);而原生SQL的JOIN逻辑如果没有合理利用索引(比如关联字段未建索引),会进一步放大性能差距。


二、用ORM实现指定列查询的方案

方案1:仅查询BuyModel的指定列(适合已新增列的场景)

如果已经给BuyModel新增了brief_id、client_id列,响应变慢的核心原因是查询了所有列(包括新增的大字段),可以用with_entities指定仅查询验证所需的字段:

# SQLAlchemy 1.x写法
buy_record = BuyModel.query.with_entities(
    BuyModel.id,
    BuyModel.plan_id,
    BuyModel.brief_id,
    BuyModel.client_id
).filter_by(id=payload_buy_id).one()

# SQLAlchemy 2.0+推荐写法
from sqlalchemy import select

stmt = select(
    BuyModel.id,
    BuyModel.plan_id,
    BuyModel.brief_id,
    BuyModel.client_id
).where(BuyModel.id == payload_buy_id)
buy_record = db.session.execute(stmt).one()

这样查询只会获取指定的4个列,不会加载其他新增的冗余字段,大幅减少数据传输和IO开销。

方案2:不新增列,通过关联查询获取数据(还原原生SQL逻辑)

如果不想给BuyModel新增列,而是通过关联表获取brief_id、client_id,可以用ORM的JOIN+指定列查询实现原生SQL的逻辑:
假设模型关系定义为:

class BuyModel(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    plan_id = db.Column(db.Integer, db.ForeignKey('plan.id'))
    plan = db.relationship('Plan')

class Plan(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    brief_id = db.Column(db.Integer, db.ForeignKey('brief.id'))
    brief = db.relationship('Brief')

class Brief(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    client_id = db.Column(db.Integer)

查询代码可以写为:

# SQLAlchemy 1.x写法
buy_data = BuyModel.query.join(BuyModel.plan)\
                         .join(Plan.brief)\
                         .with_entities(
                             BuyModel.id,
                             BuyModel.plan_id,
                             Plan.brief_id,
                             Brief.client_id
                         ).filter(BuyModel.id == payload_buy_id)\
                         .one()

# SQLAlchemy 2.0+推荐写法
stmt = select(
    BuyModel.id,
    BuyModel.plan_id,
    Plan.brief_id,
    Brief.client_id
).join(Plan, BuyModel.plan_id == Plan.id)\
.join(Brief, Plan.brief_id == Brief.id)\
.where(BuyModel.id == payload_buy_id)
buy_data = db.session.execute(stmt).one()

这种方式和原生SQL逻辑完全一致,但能利用ORM的缓存、索引优化等特性,性能会比手写原生SQL更稳定。


内容的提问来源于stack exchange,提问作者maximosis

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.18 02:37:13