nexus-plugin-prisma: Possible bug: Nexus-prisma is causing multiple queries to be run for a single query
Background: We just implemented prisma-nexus into our project. We are using apollo-server and graphql-middleware. Upon introducing prisma-nexus, we saw a huge dip in performance during testing. This lead me to investigate.
Problem: I’m seeing some extremely inefficient behavior with queries generated by nexus-prisma. Sometimes at a point where my prisma DB gets overloaded by queries and becomes unresponsive for a second or two. There’s a lot of cases I’m seeing where it seems nexus-prisma is taking one query and breaking them out into multiple queries (the highest I saw was 213 queries). I’ve just picked two to illustrate my point.
It seems the issue arises when the query is selecting relational properties and enum properties. The first query I’m sending through illustrates the relational properties issue. The second illustrates enum properties. These show the query inefficiencies.
Note 1: I’ve turned on query logging on my prisma DB. This is how I was able to see this and grab the queries. Note 2: Worried that my team and I had done something wrong with our implementation, I cloned the repo and ran the example (nexus-prisma/example) code against my prisma DB and saw the exact same behavior.
QUERY 1
query {
userProfiles(where:{id:"cjoal2g9501im08129j5xc6kv"}) {
id
favorites{title}
}
}
Note: favorites is the relation property (array of Favorite)
Results in 2 prisma queries being run:
This one gets ALL non-relational properties for the UserProfile … even though we’re just querying for id and favorites.
[{"query":"query ($where: UserProfileWhereInput) {
userProfiles(where: $where) {
id
oktaId
firstName
lastName
userName
email
phone
status
countryCode
profilePicture
location
pending
defaultLandingPage
dateFormat
timeFormat
lastActive
accountAdmin
programAdmin
employee
authId
createdAt
updatedAt
}
}
","variables":{"where":{"id":"cjoal2g9501im08129j5xc6kv"}}}]
This one just gets the Favorite (relational property) and all non-relational properties of the Favorite
[{"query":"query ($where: UserProfileWhereUniqueInput!) {
userProfile(where: $where) {
favorites {
id
title
url
subdomain
relativePath
openNewTab
sortOrder
createdAt
updatedAt
}
}
}
","variables":{"where":{"id":"cjoal2g9501im08129j5xc6kv"}}}]
QUERY 2
query {
userProfiles(where:{}) {
status
}
}
Note:Status is UserProfileStatus, an enum.
There are 82 UserProfiles Results in 83 (!) prisma queries (this only happens when including an enum value in the query):
The preliminary one; gets ALL non-relational properties for the UserProfile
[{"query":"query ($where: UserProfileWhereInput) {
userProfiles(where: $where) {
id
oktaId
firstName
lastName
userName
email
phone
status
countryCode
profilePicture
location
pending
defaultLandingPage
dateFormat
timeFormat
lastActive
accountAdmin
programAdmin
employee
authId
createdAt
updatedAt
}
}
","variables":{"where":{}}}]
The next 82 are the same query…just querying on status for each UserProfile:
[{"query":"query ($where: UserProfileWhereUniqueInput!) {
userProfile(where: $where) {
status
}
}
","variables":{"where":{"id":"cjoal2g9501im08129j5xc6kv"}}}
,{"query":"query ($where: UserProfileWhereUniqueInput!) {
userProfile(where: $where) {
status
}
}
","variables":{"where":{"id":"cjoeybj5702r30812g6fmz24d"}}}
...
80 more queries - all with different ids
...
]
Here’s our relevant types for the datamodel.prisma file:
type UserProfile {
id: ID! @unique
oktaId: ID
firstName: String!
lastName: String!
userName: String
email: String! @unique
phone: String
--> status: UserProfileStatus!
userGroup: UserGroup
--> favorites: [Favorite!]!
notifications: [Notification!]!
countryCode: String
profilePicture: String
location: String
pending: Boolean
defaultLandingPage: LandingPage
dateFormat: String
timeFormat: String
lastActive: String
accountAdmin: Boolean! @default(value: "false")
programAdmin: Boolean! @default(value: "false")
employee: Boolean! @default(value: "false")
userPrograms: [UserProgram!]! @relation(name: "UserAndUserProgram" onDelete: CASCADE)
authId: String! @unique
accountUsers: [AccountUser!]! @relation(name: "UserAndAccountUser" onDelete: CASCADE)
createdAt: DateTime!
updatedAt: DateTime!
}
type Favorite {
id: ID! @unique
title: String!
url: String
subdomain: String
relativePath: String
openNewTab: Boolean!
sortOrder: Int!
users: [UserProfile!]!
createdAt: DateTime!
updatedAt: DateTime!
}`
enum UserProfileStatus {
DISABLED
LOCKED
ACTIVE
}
About this issue
- Original URL
- State: closed
- Created 5 years ago
- Reactions: 1
- Comments: 16 (6 by maintainers)
Prisma Client has optimized
findOnequeries since2.0.0-preview023, see the headlineOptimize nested GraphQL queries that use Prisma Client ("dataloader")on https://github.com/prisma/prisma2/releases/tag/2.0.0-preview023If you upgrade to that version @Linktheoriginal you should see a definitive improvement.
We would be very interested in before/after comparisons by the way if you have the capacity to measure the queries a bit etc. Understanding the impact of this change would be really nice.
Ok. We’ve evaluated and the enum issue is resolved. Thanks for that.
However, we’re still seeing inefficient queries with relational properties.
Here’s a somewhat straightforward explanation of what I’m still seeing: I’m seeing nexus breaking up one query into multiple queries. In almost all cases this is causing multiple queries being run. These queries grab more properties than needed and repeat for the number of records they are querying against. Here’s a simplified example:
Here’s the schema:
type User {id: IDemail: Stringname: Stringposts: [Post]}type Post {id: ID!createdAt: DateTimeupdatedAt: DateTimepublished: Booleantitle: Stringtype:PostTypecontent: Stringauthor: User}enum PostType{AUTOMANUAL}Let’s say I have 2 Users and 3 posts in the DB. When running this query:
{posts(where:{}){id author{id}}}It results in 3 queries sent to prisma. One query for each post. And the queries are for all the properties on both types.
Example of nexus-generated query:
{"query":"query ($where: PostWhereUniqueInput!) {post(where: $where) {author {idemailname}}}","variables":{"where":{"id":"cjujykxsx00270708hyu8rt4d"}}},{"query":"query ($where: PostWhereUniqueInput!) {post(where: $where) {author {idemailname}}}","variables":{"where":{"id":"cjujyv7tb00370708vdqvwa49"}}},{"query":"query ($where: PostWhereUniqueInput!) {post(where: $where) {author {idemailname}}}","variables":{"where":{"id":"cjuk7told007l07441076g6rs"}}},{"query":"query ($where: PostWhereUniqueInput!) {post(where: $where) {author {idemailname}}}","variables":{"where":{"id":"cjuk7w4s300a30744rwmj4nwt"}}}I’m not sure why it’s querying for each
Post, but it seems like a bug.@LarsJK to be clear a dedupe cache is something Prisma Client could do one day too. It’s just unclear as a priority. It falls under the responsibilities of what dataloader does 😃 I’m not on the core team this is just me speaking from discussions I’ve head with @timsuchanek. I think for schemas with highly cyclical relations that also show up in client queries then deduping could be a major benefit. Will be interesting to see how much the community asks for it in practice.
Maybe related to this issue? https://github.com/prisma/prisma/issues/3599