预加载
大约 2 分钟
预加载
为避免 N+1 查询,Sea-ORM 提供 LoaderTrait 的批量预加载能力,以及 find_with_related
的聚合查询。
load_one / load_many(LoaderTrait)
use sea_orm::LoaderTrait;
// 1) 批量查用户
let users = entity::sys_user::Entity::find().all(&db).await?;
// 2) 预加载所属部门(多对一)
let depts: Vec<Option<entity::sys_dept::Model>> = users.load_one(entity::sys_dept::Entity, &db).await?;
// 3) 预加载用户的角色(多对多)
let roles: Vec<Vec<entity::sys_role::Model>> = users.load_many(entity::sys_role::Entity, &db).await?;
// 4) 组装 VO
#[derive(serde::Serialize)]
struct UserWithRel {
user: entity::sys_user::Model,
dept: Option<entity::sys_dept::Model>,
roles: Vec<entity::sys_role::Model>,
}
let items: Vec<UserWithRel> = users.into_iter().zip(depts).zip(roles)
.map(|((u, d), rs)| UserWithRel { user: u, dept: d, roles: rs })
.collect();
load_one
返回与主集合等长的 Option 向量load_many
返回与主集合等长的 Vec 向量
find_with_related
将一对多/多对多结果聚合为 (Model, Vec<RelatedModel>)
:
// 角色及其权限列表(role has_many perm 例)
let rows: Vec<(entity::sys_role::Model, Vec<entity::sys_perm::Model>)> =
entity::sys_role::Entity::find()
.find_with_related(entity::sys_perm::Entity)
.all(&db).await?;
分页聚合:
use sea_orm::PaginatorTrait;
let find = entity::sys_role::Entity::find().find_with_related(entity::sys_perm::Entity);
let paginator = find.paginate(&db, 20);
let page_items = paginator.fetch_page(0).await?;
选择列与过滤
在预加载/聚合前可对主查询或关联查询进行过滤与选择列:
use sea_orm::{QueryFilter, ColumnTrait};
let users = entity::sys_user::Entity::find()
.filter(entity::sys_user::Column::Status.eq(1))
.all(&db).await?;
let roles = users.load_many(entity::sys_role::Entity, &db).await?;
性能建议
- 优先选择
load_*
替代在循环里逐个find_related
(避免 N+1) - 对大集合分页,再按页预加载关联
- 仅选择需要的列(
select_only + column
)降低传输量 - 对多对多,确保中间表(user_role)有合适索引