TypeORM为何执行含多OR语句的关联ID查询?性能优化求助
问题背景
使用NestJS + TypeORM + MySQL架构,通过RDS性能洞察发现一条频繁触发的低效查询,已引发性能问题:
SELECT
user_auth.idASid,user_auth.user_idASuser_id
FROMuser_authuser_auth
WHERE ((user_auth.user_id= ?)
OR (user_auth.user_id= ?)
OR (user_auth.user_id= ?)
OR ...)
代码中未手动编写过该批量查询逻辑,怀疑与User和UserAuth的OneToOne关联配置有关,实体代码如下:
user-auth.entity.ts
@Field(() => User) @OneToOne(() => User, (user) => user.auth, { createForeignKeyConstraints: false, }) @JoinColumn({ name: 'user_id' }) user: User; @Field(() => ID) @RelationId((userAuth: UserAuth) => userAuth.user) userId: number;
user.entity.ts
@Field(() => UserAuth, { nullable: true, }) @OneToOne(() => UserAuth, (userAuth) => userAuth.user) auth: UserAuth; @Field(() => ID) @RelationId((user: User) => user.auth) authId: number;
触发原因
这条查询是TypeORM自动生成的,根源在于User实体中的@RelationId((user) => user.auth):
- 当查询多个User实体(比如
find()、findAndCount()等批量操作)时,TypeORM会自动执行这条批量查询,用来获取每个User对应的authId值 - 生成多个
OR条件而非IN,可能是TypeORM版本特性或关联配置细节导致,但本质是为了批量匹配user_id,获取对应的user_auth.id作为authId
性能优化方案
1. 添加索引(最紧急)
针对user_auth表的user_id字段添加索引,直接解决查询性能瓶颈:
CREATE INDEX idx_user_auth_user_id ON user_auth(user_id);
该索引会让MySQL快速定位匹配的user_id记录,大幅降低查询延迟和等待负载。
2. 优化关联加载逻辑
避免TypeORM自动生成批量查询,改为手动关联查询:
在查询User时,手动关联user_auth并直接获取authId,替代@RelationId的自动加载:
// 示例:UserService中的查询方法 async getUsers() { return this.userRepository.createQueryBuilder('user') .leftJoin('user.auth', 'auth') .select([ 'user.id', 'user.username', // 按需添加其他User字段 'auth.id as authId' // 手动指定authId ]) .getMany(); }
同时可考虑移除User实体中的@RelationId字段,避免自动触发查询。
3. 调整TypeORM关联配置
如果需要保留@RelationId,检查是否开启了eager自动加载(若开启会强制自动关联查询),必要时关闭:
// 修改User实体的auth关联配置 @OneToOne(() => UserAuth, (userAuth) => userAuth.user, { eager: false }) auth: UserAuth;
4. 升级TypeORM版本
部分旧版TypeORM在处理批量@RelationId查询时,会生成低效的OR语句而非IN,升级到最新稳定版(如0.3.x系列)可能会自动优化为IN条件,提升查询效率。
内容的提问来源于stack exchange,提问作者Woojin Lee

