Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Query for empty relations is very slow for many-to-many relation #25731

Closed
vimutti77 opened this issue Nov 27, 2024 · 8 comments · Fixed by prisma/prisma-engines#5104
Closed
Labels
bug/1-unconfirmed Bug should have enough information for reproduction, but confirmation has not happened yet. domain/client Issue in the "Client" domain: Prisma Client, Prisma Studio etc. kind/bug A reported bug. tech/engines Issue for tech Engines. topic: m:n many-to-many relations topic: performance/queries topic: performance

Comments

@vimutti77
Copy link

Bug description

I have a schema with many-to-many relation like this

model User {
  id     String  @id
  issues Issue[]
}

model Issue {
  id        String @id
  assignees User[]
}

I insert the data to database by using this SQL

INSERT INTO "User" ("id")
SELECT * FROM generate_series(1, 100) ;

INSERT INTO "Issue" ("id")
SELECT * FROM generate_series(1, 100000) ;

INSERT INTO "_IssueToUser" ("A", "B")
SELECT * FROM generate_series(1, 100000) AS A, generate_series(1, 100) AS B;

I want to count the Issue that have empty assignees by using prisma.issue.count({ where: { assignees: { none: {} } } })
But it takes about 1-2 mins to get the result.

How to reproduce

  1. Create schema with many-to-many relation
  2. Insert mock data
  3. Count the items that relation is empty

Expected behavior

It should be fast

Prisma information

model User {
  id     String  @id
  issues Issue[]
}

model Issue {
  id        String @id
  assignees User[]
}
// Add your code using Prisma Client
prisma.issue.count({ where: { assignees: { none: {} } } })

Environment & setup

  • OS: Windows, Linux
  • Database: PostgreSQL
  • Node.js version: 20

Prisma Version

prisma                  : 5.22.0
@prisma/client          : 5.22.0
Computed binaryTarget   : windows
Operating System        : win32
Architecture            : x64
Node.js                 : v20.13.1
Query Engine (Node-API) : libquery-engine 605197351a3c8bdd595af2d2a9bc3025bca48ea2 (at node_modules\.pnpm\@[email protected]\node_modules\@prisma\engines\query_engine-windows.dll.node)
Schema Engine           : schema-engine-cli 605197351a3c8bdd595af2d2a9bc3025bca48ea2 (at node_modules\.pnpm\@[email protected]\node_modules\@prisma\engines\schema-engine-windows.exe)  
Schema Wasm             : @prisma/prisma-schema-wasm 5.22.0-44.605197351a3c8bdd595af2d2a9bc3025bca48ea2
Default Engines Hash    : 605197351a3c8bdd595af2d2a9bc3025bca48ea2
Studio                  : 0.503.0
@vimutti77 vimutti77 added the kind/bug A reported bug. label Nov 27, 2024
@vimutti77
Copy link
Author

vimutti77 commented Nov 28, 2024

The SQL from prisma is using NOT IN which is very slow in this case (total time ~1.30 mins).

SELECT COUNT(*)
FROM (
  SELECT "public"."Issue"."id"
  FROM "public"."Issue"
  WHERE ("public"."Issue"."id") NOT IN (
    SELECT "t1"."A"
	FROM "public"."_IssueToUser" AS "t1"
	INNER JOIN "public"."User" AS "j1"
	ON ("j1"."id") = ("t1"."B")
	WHERE (1=1 AND "t1"."A" IS NOT NULL)
  )
) AS "sub"

I modified it to use NOT EXISTS instead, which speeds up the query significantly (total time ~0.5 secs).

SELECT COUNT(*)
FROM (
  SELECT "public"."Issue"."id"
  FROM "public"."Issue"
  WHERE NOT EXISTS (
    SELECT "t1"."A"
	FROM "public"."_IssueToUser" AS "t1"
	INNER JOIN "public"."User" AS "j1"
	ON ("j1"."id") = ("t1"."B")
	WHERE ("public"."Issue"."id" = "t1"."A")
  )
) AS "sub"

@aqrln aqrln added bug/1-unconfirmed Bug should have enough information for reproduction, but confirmation has not happened yet. topic: performance domain/client Issue in the "Client" domain: Prisma Client, Prisma Studio etc. topic: m:n many-to-many relations topic: performance/queries tech/engines Issue for tech Engines. labels Nov 29, 2024
@vimutti77
Copy link
Author

This issue may be related to #24524.
The problem is prisma using IN / NOT IN for filtering relationship which is very inefficient for large table.

@jacek-prisma
Copy link
Contributor

jacek-prisma commented Jan 8, 2025

Hi @vimutti77, @senorverde-tc and @Sjlver,
I've published a dev version which uses correlated subqueries for all relational filters, it'd be good to get some feedback on whether it performs better in typical user workloads, it's been published as:
prisma@6.3.0-integration-engines-6-3-0-1-feat-relation-exists-aff8bf73313e0df76046e671a2cb2d31491601a3.5

If you can offer some feedback on it that'd be great.

@Sjlver
Copy link

Sjlver commented Jan 8, 2025

Hi @jacek-prisma, thanks so much for working on this!

I can give this a try mid next week, around Jan 15. To make sure I understand: I need to specify prisma@6.3.0-integration-engines-6-3-0-1-feat-relation-exists-aff8bf73313e0df76046e671a2cb2d31491601a3.3 in my package.json file as the prisma version? Do I need the same for @prisma/client?

@jacek-prisma
Copy link
Contributor

jacek-prisma commented Jan 8, 2025

Hi @Sjlver. yes, these are the two NPM packages:

  • prisma@6.3.0-integration-engines-6-3-0-1-feat-relation-exists-aff8bf73313e0df76046e671a2cb2d31491601a3.5
    @prisma/client@6.3.0-integration-engines-6-3-0-1-feat-relation-exists-aff8bf73313e0df76046e671a2cb2d31491601a3.5

@vimutti77
Copy link
Author

@jacek-prisma I have upgraded to the version you mentioned, but it still uses IN. What else do I need to do?

image

Prisma Version

prisma                  : 6.3.0-integration-engines-6-3-0-2-integration-sql-nested-transactions5-9a074425ccc05b5ec12b88ec141ba5dea21472b7.2
@prisma/client          : 6.3.0-integration-engines-6-3-0-2-integration-sql-nested-transactions5-9a074425ccc05b5ec12b88ec141ba5dea21472b7.2
Computed binaryTarget   : windows
prisma                  : 6.3.0-integration-engines-6-3-0-2-integration-sql-nested-transactions5-9a074425ccc05b5ec12b88ec141ba5dea21472b7.2
@prisma/client          : 6.3.0-integration-engines-6-3-0-2-integration-sql-nested-transactions5-9a074425ccc05b5ec12b88ec141ba5dea21472b7.2
Computed binaryTarget   : windows
Operating System        : win32
Architecture            : x64
Node.js                 : v20.13.1
TypeScript              : 5.4.5
Query Engine (Node-API) : libquery-engine 9a074425ccc05b5ec12b88ec141ba5dea21472b7 (at node_modules\.pnpm\@prisma+engines@6.3.0-integration-engines-6-3-0-2-integration-sql-nested-transactions5-9a0744_kt6xdhq7jmyzsepmxwuvshgjom\node_modules\@prisma\engines\query_engine-windows.dll.node)
Schema Engine           : schema-engine-cli 9a074425ccc05b5ec12b88ec141ba5dea21472b7 (at node_modules\.pnpm\@prisma+engines@6.3.0-integration-engines-6-3-0-2-integration-sql-nested-transactions5-9a0744_kt6xdhq7jmyzsepmxwuvshgjom\node_modules\@prisma\engines\schema-engine-windows.exe)
Schema Wasm             : @prisma/prisma-schema-wasm 6.3.0-2.integration-sql-nested-transactions5-9a074425ccc05b5ec12b88ec141ba5dea21472b7
Default Engines Hash    : 9a074425ccc05b5ec12b88ec141ba5dea21472b7
Studio                  : 0.503.0

@jacek-prisma
Copy link
Contributor

Sorry @vimutti77 , I've listed the wrong version, I just updated the comment with the correct one!

@vimutti77
Copy link
Author

Thanks @jacek-prisma. I did some initial testing, and the query time was reduced to 0.5 seconds! I haven't encountered any issues yet.

image

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug/1-unconfirmed Bug should have enough information for reproduction, but confirmation has not happened yet. domain/client Issue in the "Client" domain: Prisma Client, Prisma Studio etc. kind/bug A reported bug. tech/engines Issue for tech Engines. topic: m:n many-to-many relations topic: performance/queries topic: performance
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants