我如何导致 NestJs TypeOrm 出现 n + 1 个问题?
How do I cause n + 1 problems with NestJs TypeOrm?
我正在研究 TypeOrm 并试图创建一个 N+1 问题,但它没有正常发生。公司和员工有 1:N 关系。
你能告诉我为什么 N + 1 没有引起任何问题吗?我试过设置 Lazy 和 Eager,但我一直在连续进行左连接,这样 n + 1 就不会引起问题。
实体
@Entity('COMPANY')
export class Company extends TimeStamped {
@PrimaryGeneratedColumn('increment')
companyId: number;
@Column({ type: 'varchar' })
companyName: string;
@OneToMany(() => Employee, (employee) => employee.company, {
onDelete: 'CASCADE'
})
employee: Employee[];
}
@Entity('EMPLOYEE')
export class Employee extends TimeStamped {
@PrimaryGeneratedColumn('increment')
employeeId: number;
@Column({ type: 'varchar' })
employeeName: string;
@ManyToOne(() => Company, (company) => company.employee)
@JoinColumn([{ name: 'companyId', referencedColumnName: 'companyId' }])
company: Company;
}
杂物
@Injectable()
export class CompanyService {
constructor(
@InjectRepository(Company)
private readonly companyRepository: Repository<Company>
) {}
getAllCompany() {
return this.companyRepository.find({ relations: ['employee'] });
}
getCompany(companyId: number) {
return this.companyRepository.findOne(companyId, {
relations: ['employee']
});
}
setCompany(setComanyDto: SetCompanyDto) {
return this.companyRepository.save(setComanyDto);
}
}
@Injectable()
export class EmployeeService {
constructor(
@InjectRepository(Employee)
private readonly employeeRepository: Repository<Employee>,
@InjectRepository(Company)
private readonly companyRepository: Repository<Company>
) {}
getAllEmployee() {
return this.employeeRepository.find({
relations: ['company']
});
}
getEmployee(employeeId: number) {
return this.employeeRepository.findOne(employeeId, {
relations: ['company']
});
}
async setEmployee(setEmployeeDto: SetEmployeeDto) {
const employee: Employee = new Employee();
employee.employeeName = setEmployeeDto.employeeName;
employee.company = await this.companyRepository.findOne(
setEmployeeDto.companyId
);
return this.employeeRepository.save(employee);
}
}
我相信你对什么是 N+1 问题很清楚。需要更清楚理解的可以查看this question
如果您使用 eager
加载,您将不会看到 N+1 问题,因为它在一个查询中加入了相关实体和 return 这两个实体。
如果您按照下面的方式指定 relations
,您将不会再次看到 N+1 问题,因为它创建了一个连接查询并且 return 全部在 1 个查询中。
this.companyRepository.find({ relations: ['employee'] });
要创建 N+1 问题,
更新您的 Company
实体,如下所示:
@Entity('COMPANY')
export class Company extends TimeStamped {
@PrimaryGeneratedColumn('increment')
companyId: number;
@Column({ type: 'varchar' })
companyName: string;
@OneToMany(() => Employee, (employee) => employee.company, {
onDelete: 'CASCADE',
lazy: true
})
employee: Promise<Employee[]>
}
在你的 CompanyService
中,创建一个新函数来模拟 N+1 问题,如下所示:
@Injectable()
export class CompanyService {
async createNPlus1Problem() {
// Query all companies (let's say you have N number of companies)
// SELECT * FROM "COMPANY";
const companies = this.companyRepository.find();
// The following `for` loop, loops through all N number of
// companies to get the employee data of each
for(company of companies) {
// Query employees of each company
// SELECT * FROM "EMPLOYEE" WHERE "companyId"=?;
const employees = await company.employee;
}
}
}
因此在上面的示例中,您有 1
查询来获取公司数据。并且 N
查询以获取员工数据。因此 N+1 问题。
希望这能澄清您的问题。干杯!!!
我正在研究 TypeOrm 并试图创建一个 N+1 问题,但它没有正常发生。公司和员工有 1:N 关系。
你能告诉我为什么 N + 1 没有引起任何问题吗?我试过设置 Lazy 和 Eager,但我一直在连续进行左连接,这样 n + 1 就不会引起问题。
实体
@Entity('COMPANY')
export class Company extends TimeStamped {
@PrimaryGeneratedColumn('increment')
companyId: number;
@Column({ type: 'varchar' })
companyName: string;
@OneToMany(() => Employee, (employee) => employee.company, {
onDelete: 'CASCADE'
})
employee: Employee[];
}
@Entity('EMPLOYEE')
export class Employee extends TimeStamped {
@PrimaryGeneratedColumn('increment')
employeeId: number;
@Column({ type: 'varchar' })
employeeName: string;
@ManyToOne(() => Company, (company) => company.employee)
@JoinColumn([{ name: 'companyId', referencedColumnName: 'companyId' }])
company: Company;
}
杂物
@Injectable()
export class CompanyService {
constructor(
@InjectRepository(Company)
private readonly companyRepository: Repository<Company>
) {}
getAllCompany() {
return this.companyRepository.find({ relations: ['employee'] });
}
getCompany(companyId: number) {
return this.companyRepository.findOne(companyId, {
relations: ['employee']
});
}
setCompany(setComanyDto: SetCompanyDto) {
return this.companyRepository.save(setComanyDto);
}
}
@Injectable()
export class EmployeeService {
constructor(
@InjectRepository(Employee)
private readonly employeeRepository: Repository<Employee>,
@InjectRepository(Company)
private readonly companyRepository: Repository<Company>
) {}
getAllEmployee() {
return this.employeeRepository.find({
relations: ['company']
});
}
getEmployee(employeeId: number) {
return this.employeeRepository.findOne(employeeId, {
relations: ['company']
});
}
async setEmployee(setEmployeeDto: SetEmployeeDto) {
const employee: Employee = new Employee();
employee.employeeName = setEmployeeDto.employeeName;
employee.company = await this.companyRepository.findOne(
setEmployeeDto.companyId
);
return this.employeeRepository.save(employee);
}
}
我相信你对什么是 N+1 问题很清楚。需要更清楚理解的可以查看this question
如果您使用 eager
加载,您将不会看到 N+1 问题,因为它在一个查询中加入了相关实体和 return 这两个实体。
如果您按照下面的方式指定 relations
,您将不会再次看到 N+1 问题,因为它创建了一个连接查询并且 return 全部在 1 个查询中。
this.companyRepository.find({ relations: ['employee'] });
要创建 N+1 问题,
更新您的 Company
实体,如下所示:
@Entity('COMPANY')
export class Company extends TimeStamped {
@PrimaryGeneratedColumn('increment')
companyId: number;
@Column({ type: 'varchar' })
companyName: string;
@OneToMany(() => Employee, (employee) => employee.company, {
onDelete: 'CASCADE',
lazy: true
})
employee: Promise<Employee[]>
}
在你的 CompanyService
中,创建一个新函数来模拟 N+1 问题,如下所示:
@Injectable()
export class CompanyService {
async createNPlus1Problem() {
// Query all companies (let's say you have N number of companies)
// SELECT * FROM "COMPANY";
const companies = this.companyRepository.find();
// The following `for` loop, loops through all N number of
// companies to get the employee data of each
for(company of companies) {
// Query employees of each company
// SELECT * FROM "EMPLOYEE" WHERE "companyId"=?;
const employees = await company.employee;
}
}
}
因此在上面的示例中,您有 1
查询来获取公司数据。并且 N
查询以获取员工数据。因此 N+1 问题。
希望这能澄清您的问题。干杯!!!