Prisma发出的查询
在我们的项目中,我们使用Prisma作为ORM来操作数据库。遇到的问题是,当尝试获取多个表的数据时,Prisma发出了多个查询,而非预期的单个联合查询。以下是一个简单的示例:
await this.prisma.company.findUnique({
where: { id },
include: {
shop: true,
},
});
许多人可能会期望发出如下的SQL查询:
SELECT *
FROM company c
JOIN shop s ON c.id = s.company_id
WHERE c.id = @id;
然而,实际发出的查询是分为两个单独的查询:
SELECT
company.id,
company.name,
company.created_at,
company.updated_at
FROM company
WHERE company.id = @id
LIMIT 1;
SELECT
shop.id,
shop.name,
shop.created_at,
shop.updated_at
FROM shop
WHERE shop.company_id IN (@company_id);
虽然这些查询能完成任务,但相比之下,使用JOIN的查询会更高效。
项目中的GraphQL使用
在我们的项目中,前端通过GraphQL与后端进行通信。虽然GraphQL与REST API相比,联合查询多个表的情况较少,但考虑到服务的未来发展和扩展性,这一问题不容忽视。
使用Raw Query绕过问题
为了规避这种不理想的查询方式,我们可以使用原生SQL查询。然而,随着2024年1月10日,Prisma预览功能推出了relationJoins
,这为我们提供了更优的解决方案。
什么是relationJoins
?
relationJoins
是Prisma的新功能,允许我们选择是否将查询联合起来。通过启用此功能,我们能够以更高效的方式处理多个表的查询。此功能已在以下版本中推出:
- PostgreSQL: v5.8.0(自2024年1月10日起)
- MySQL: v5.10.0(自2024年2月21日起)
如何使用relationJoins
要启用relationJoins
,首先需要在prisma.schema
文件中配置该功能,然后运行npx prisma generate
来生成客户端代码:
generator client {
provider = "prisma-client-js"
engineType = "binary"
previewFeatures = ["relationJoins"]
}
启用后,您可以设置relationLoadStrategy
为join
,并通过Prisma发出JOIN查询。
await this.prismaService.company.findUnique({
relationLoadStrategy: "join",
where: { databaseId },
include: {
shop: true,
},
});
此时,Prisma会发出以下SQL查询:
SELECT `t1`.`id`,`t1`.`name`,`t1`.`created_at` AS `createdAt`,`t1`.`updated_at` AS `updatedAt`,
(
SELECT COALESCE(JSON_ARRAYAGG(`__prisma_data__),CONVERT('[]', JSON)) AS `__prisma_data__`
FROM (
SELECT `t4`.`__prisma_data__`
FROM (
SELECT JSON_OBJECT('id',`t3`.`id`,'name',`t3`.`name`,'createdAt',`t3`.`created_at`,'updatedAt',`t3`.`updated_at`) AS `__prisma_data__`
FROM(
SELECT `t2`.*
FROM `shop` AS `t2`
WHERE `t1`.`id` = `t2`.`company_id`
) AS `t3`
) AS `t4`
) AS `t5`
) AS `shops`
FROM `company` AS `t1`
WHERE (`t1`.`id` = @id)
LIMIT 1;
虽然发出的查询比我们预期的要复杂,但它通过嵌套的子查询而非传统的JOIN方式来获取数据。
发布计划
尽管relationJoins
功能的实际查询行为与预期有所偏差,Prisma团队仍计划对其进行进一步优化。
根据2024年11月14日的讨论,Prisma团队尚未宣布正式版本发布的具体计划,但该功能的改进工作已经提上日程,且将优先处理。
评论(0)