MichalLytek / typegraphql-prisma

Prisma generator to emit TypeGraphQL types and CRUD resolvers from your Prisma schema
https://prisma.typegraphql.com
MIT License
891 stars 113 forks source link

N+1 select issue due to use of findUniqueOrThrow in relation resolvers #383

Closed sam-lewis closed 1 year ago

sam-lewis commented 1 year ago

Describe the Bug It appears that the switch to findUniqueOrThrow() in https://github.com/MichalLytek/typegraphql-prisma/commit/3ea20f65b030311d384a457c62b84deab1fc1d46 has introduced an N+1 select issue.

I have observed that Prisma's built-in dataloader batches findUnique() queries but not findUniqueOrThrow()queries resulting in N+1 selects in recent versions of typegraphql-prisma.

To Reproduce

Expected Behavior Fewer select statements against the database as seen with previous versions (see logs below)

Logs With typegraphql-prisma 0.25.0:

prisma:query SELECT `main`.`User`.`id`, `main`.`User`.`email`, `main`.`User`.`name` FROM `main`.`User` WHERE 1=1 LIMIT ? OFFSET ?
prisma:query SELECT `main`.`User`.`id` FROM `main`.`User` WHERE (`main`.`User`.`id` = ? AND 1=1) LIMIT ? OFFSET ?
prisma:query SELECT `main`.`Post`.`id`, `main`.`Post`.`createdAt`, `main`.`Post`.`updatedAt`, `main`.`Post`.`published`, `main`.`Post`.`title`, `main`.`Post`.`content`, `main`.`Post`.`authorId` FROM `main`.`Post` WHERE `main`.`Post`.`authorId` IN (?) LIMIT ? OFFSET ?
prisma:query SELECT `main`.`User`.`id` FROM `main`.`User` WHERE (`main`.`User`.`id` = ? AND 1=1) LIMIT ? OFFSET ?
prisma:query SELECT `main`.`Post`.`id`, `main`.`Post`.`createdAt`, `main`.`Post`.`updatedAt`, `main`.`Post`.`published`, `main`.`Post`.`title`, `main`.`Post`.`content`, `main`.`Post`.`authorId` FROM `main`.`Post` WHERE `main`.`Post`.`authorId` IN (?) LIMIT ? OFFSET ?

With typegraphql-prisma 0.23.2:

prisma:query SELECT `main`.`User`.`id`, `main`.`User`.`email`, `main`.`User`.`name` FROM `main`.`User` WHERE 1=1 LIMIT ? OFFSET ?
prisma:query SELECT `main`.`User`.`id` FROM `main`.`User` WHERE `main`.`User`.`id` IN (?,?) LIMIT ? OFFSET ?
prisma:query SELECT `main`.`Post`.`id`, `main`.`Post`.`createdAt`, `main`.`Post`.`updatedAt`, `main`.`Post`.`published`, `main`.`Post`.`title`, `main`.`Post`.`content`, `main`.`Post`.`authorId` FROM `main`.`Post` WHERE `main`.`Post`.`authorId` IN (?,?) LIMIT ? OFFSET ?

Environment:

Additional Context Nice work on the project, its awesome :-)

cdimino commented 1 year ago

I believe we're seeing this issue as well.

Could the Prisma team add findUniqueOrThrow to their list of "dataloader approved" funcs to resolve this? Or would typegraphql-prisma need to generate slightly different models? I've been reading through the fluent API, could that be used here?

cdimino commented 1 year ago

I was able to get around this in my specific implementation, and by using Prisma's Fluent API I got a 97% perf boost (!!!).

IDK how hard it would be to get the generated code to make use of the Fluent API, but if you see an easy way that might help this category of issue.

https://www.prisma.io/docs/concepts/components/prisma-client/relation-queries#fluent-api

sam-lewis commented 1 year ago

I was able to get around this in my specific implementation, and by using Prisma's Fluent API I got a 97% perf boost (!!!).

How does that compare to manually editing the generated relation resolver code to use findUnique()?

cdimino commented 1 year ago

How does that compare to manually editing the generated relation resolver code to use findUnique()?

Oh yeah actually really good as well, probably here the only value of the Fluent API was to get the dataloader to pay attention, then.

mc-nekoneko commented 1 year ago

For reference, I am managed to handle it forcibly with middleware, as shown in the following link. πŸ˜’ https://github.com/prisma/prisma/issues/18838#issuecomment-1547295065

MichalLytek commented 1 year ago

Closing as looks like it's fixed by https://github.com/prisma/prisma/issues/16625 πŸ”’

@sam-lewis If the issue still occurs, please let me know πŸ˜‰