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

Schema size affects runtime speed #14695

Closed
DarioSiroki opened this issue Aug 8, 2022 · 4 comments · Fixed by #14712
Closed

Schema size affects runtime speed #14695

DarioSiroki opened this issue Aug 8, 2022 · 4 comments · Fixed by #14712
Labels
bug/2-confirmed Bug has been reproduced and confirmed. kind/regression A reported bug in functionality that used to work before. team/client Issue for team Client. topic: performance
Milestone

Comments

@DarioSiroki
Copy link

DarioSiroki commented Aug 8, 2022

Bug description

After migration from 3.15.2 to 4.0.0, my production server has started running out of memory during syncs between 2 databases which occur every 45 seconds. The provided client code is a simplified version of the production code.

Test code is provided below. It builds 500 upsert queries and executes them via $transaction

Prisma 4.1.1

With 201 tables in schema:

Runtime: 48.124s
Runtime: 1.610s
Runtime: 1.578s

With 1 table in schema:

Runtime: 2.181s
Runtime: 1.509s
Runtime: 1.539s

Prisma 3.15.2

With 201 tables in schema:

Runtime: 1.691s
Runtime: 1.508s
Runtime: 1.482s

With 1 table in schema:

Runtime: 1.776s
Runtime: 1.599s
Runtime: 1.479s

By the way, this also happens with prisma.table.create. I have not tried other cases.

How to reproduce

  1. Use the provided client code with provided prisma schema.
  2. Try with prisma 4.1.1.
  3. Check runtimes and RAM/CPU usages with 1 table in schema and with 200 tables which are commented out.

There is a difference in runtime with schema size.

Expected behavior

  1. The first run shouldn't be so slow and use that much RAM. It wasn't this slow in 3.15.2.
  2. Number of tables inside schema shouldn't affect the query speed.

Prisma information

import { PrismaClient } from '@prisma/client'
import { v4 } from 'uuid'

const prisma = new PrismaClient()

export async function go() {
    const queries = []

    for (let i = 0; i < 500; i++) {
        const element = prisma.client.upsert({
            where: {
                id: i,
            },
            create: {
                username: v4(),
            },
            update: {
                username: v4(),
            },
        })
        queries.push(element)
    }

    console.time('Runtime')
    await prisma.$transaction(queries)
    console.timeEnd('Runtime')
}

async function main() {
    await go()
    await go()
    await go()
}

main()

Find the prisma schema at pastebin

Environment & setup

  • OS: Mac OS, Amazon Linux AMI
  • Database: PostgreSQL
  • Node.js version: v16.15.0

Prisma Version

prisma                  : 4.1.1
@prisma/client          : 4.1.1
Current platform        : darwin-arm64
Query Engine (Node-API) : libquery-engine 8d8414deb360336e4698a65aa45a1fbaf1ce13d8 (at node_modules/@prisma/engines/libquery_engine-darwin-arm64.dylib.node)
Migration Engine        : migration-engine-cli 8d8414deb360336e4698a65aa45a1fbaf1ce13d8 (at node_modules/@prisma/engines/migration-engine-darwin-arm64)
Introspection Engine    : introspection-core 8d8414deb360336e4698a65aa45a1fbaf1ce13d8 (at node_modules/@prisma/engines/introspection-engine-darwin-arm64)
Format Binary           : prisma-fmt 8d8414deb360336e4698a65aa45a1fbaf1ce13d8 (at node_modules/@prisma/engines/prisma-fmt-darwin-arm64)
Default Engines Hash    : 8d8414deb360336e4698a65aa45a1fbaf1ce13d8
Studio                  : 0.469.0
@DarioSiroki DarioSiroki added the kind/bug A reported bug. label Aug 8, 2022
@janpio janpio added team/client Issue for team Client. bug/1-unconfirmed Bug should have enough information for reproduction, but confirmation has not happened yet. topic: performance labels Aug 8, 2022
SevInf added a commit that referenced this issue Aug 9, 2022
Problem: when we have a freshly instantiated client (haven't done
any queries yet) and we execute multiple queries at the same event loop
tick, each one of them will start `getDMMF` request, which could be
quite slow.

Fixed by caching the results promise first time `getDMMF` is called and
returning the same promise for subsequent calls.

Fix #14695
@SevInf
Copy link
Contributor

SevInf commented Aug 9, 2022

I was able to reproduce and fix it. Here is what I am getting after the fix:

Runtime: 4.127s
Runtime: 1.912s
Runtime: 1.825s

First call is still around 2 times slower than subsequent ones, but not to the same degree as reported here. Reason why it's not quite back to the times it was before is that in 3.x we've bundled DMMF with generated client, where in 4.x we get it at runtime.

@SevInf SevInf added bug/2-confirmed Bug has been reproduced and confirmed. and removed bug/1-unconfirmed Bug should have enough information for reproduction, but confirmation has not happened yet. labels Aug 9, 2022
@SevInf
Copy link
Contributor

SevInf commented Aug 9, 2022

Update:
DMMF turned out to be red herring, after shifting couple things around, got it to roughly 3.x levels:

Runtime: 1.863s
Runtime: 1.756s
Runtime: 1.756s

The fix won't make it into 4.2.0 release, but will be published in 4.2.1 shortly afterwards. @DarioSiroki thanks for the report and great reproduction!

@DarioSiroki
Copy link
Author

No problem, thanks for the quick fix!

@Jolg42 Jolg42 added this to the 4.3.0 milestone Aug 9, 2022
SevInf added a commit that referenced this issue Aug 9, 2022
Problem: when we have a freshly instantiated client (haven't done
any queries yet) and we execute multiple queries at the same event loop
tick, each one of them will start `getDMMF` request, which could be
quite slow.

Fixed by caching the results promise first time `getDMMF` is called and
returning the same promise for subsequent calls.

Fix #14695
SevInf added a commit that referenced this issue Aug 9, 2022
Problem: when we have a freshly instantiated client (haven't done
any queries yet) and we execute multiple queries at the same event loop
tick, each one of them will start `getDMMF` request, which could be
quite slow.

Fixed by caching the results promise first time `getDMMF` is called and
returning the same promise for subsequent calls.

Fix #14695
@janpio janpio added kind/regression A reported bug in functionality that used to work before. and removed kind/bug A reported bug. labels Aug 9, 2022
SevInf added a commit that referenced this issue Aug 10, 2022
Problem: when we have a freshly instantiated client (haven't done
any queries yet) and we execute multiple queries at the same event loop
tick, each one of them will start `getDMMF` request, which could be
quite slow.

Fixed by caching the results promise first time `getDMMF` is called and
returning the same promise for subsequent calls.

Fix #14695
SevInf added a commit that referenced this issue Aug 10, 2022
Problem: when we have a freshly instantiated client (haven't done
any queries yet) and we execute multiple queries at the same event loop
tick, each one of them will start `getDMMF` request, which could be
quite slow.

Fixed by caching the results promise first time `getDMMF` is called and
returning the same promise for subsequent calls.

Fix #14695
@SevInf
Copy link
Contributor

SevInf commented Aug 10, 2022

Released in 4.2.1

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug/2-confirmed Bug has been reproduced and confirmed. kind/regression A reported bug in functionality that used to work before. team/client Issue for team Client. topic: performance
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants