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)

Most upvoted comments

Prisma Client has optimized findOne queries since 2.0.0-preview023, see the headline Optimize nested GraphQL queries that use Prisma Client ("dataloader") on https://github.com/prisma/prisma2/releases/tag/2.0.0-preview023

If 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: ID email: String name: String posts: [Post] }

type Post { id: ID! createdAt: DateTime updatedAt: DateTime published: Boolean title: String type:PostType content: String author: User }

enum PostType{ AUTO MANUAL }

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 { id email name } } } ","variables":{"where":{"id":"cjujykxsx00270708hyu8rt4d"}}},{"query":"query ($where: PostWhereUniqueInput!) { post(where: $where) { author { id email name } } } ","variables":{"where":{"id":"cjujyv7tb00370708vdqvwa49"}}},{"query":"query ($where: PostWhereUniqueInput!) { post(where: $where) { author { id email name } } } ","variables":{"where":{"id":"cjuk7told007l07441076g6rs"}}},{"query":"query ($where: PostWhereUniqueInput!) { post(where: $where) { author { id email name } } } ","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.