question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Running a statement results in different prepared statements

See original GitHub issue

Bug description

I am experiencing reaching the max_prepared_stmt_count limit in MySQL. I have found the reason to be that prisma is creating a lot of prepared statements.

We were getting information from the database and updating one field but were writing all data in the update statement. This is obviously not good and fixed on our side.

const sms = await this.prismaService.sms.findFirst({
  where: { externalId },
});

sms.status = 'delivered';

await this.prismaService.sms.update({
  data: sms,
  where: { externalId },
});
UPDATE `xxx`.`Sms` SET `body` = ?, `x` = ?, `campaignName` = ?, `p` = ?, `externalId` = ?, `sentAt` = ?, `id` = ?, `deliveredAt` = ?, `from` = ?, `bouncedAt` = ?, `updatedAt` = ?, `to` = ?, `isRestricted` = ?, `isDeleted` = ?, `y` = ?, `status` = ?, `deletedAt` = ?, `createdAt` = ? WHERE `xxx`.`Sms`.`id` IN (?)

or

UPDATE `xxx`.`Sms` SET `body` = ?, `x` = ?, `externalId` = ?, `deletedAt` = ?, `to` = ?, `y` = ?, `createdAt` = ?, `p` = ?, `bouncedAt` = ?, `deliveredAt` = ?, `from` = ?, `id` = ?, `updatedAt` = ?, `campaignName` = ?, `sentAt` = ?, `isRestricted` = ?, `status` = ?, `isDeleted` = ? WHERE `xxx`.`Sms`.`id` IN (?)

Interestingly the keys of the fetched object are not in the same order when getting them. This model has 17 fields resulting in 355.687.428.096.000 (17!) possible ways the prepared statement could be created.

How to reproduce

await this.prisma.sms.create({
  data: {
    from: 'yes',
    to: 'no',
    body: 'bla',
  },
})

await this.prisma.sms.create({
  data: {
    body: 'bla',
    from: 'yes',
    to: 'no',
  },
})

in MySQL look in performance_schema -> prepared_statements_instances and you will see two different prepared statements.

Expected behavior

I would expect that prisma normalizes this so that there is only one prepared statement. Reducing the number of prepared statements needed and thus not causing max_prepared_stmt_count errors.

Prisma information

model Sms {
  id           String    @id @default(uuid()) @db.Char(36)
  x   String?    @db.Char(36)
  from         String
  to           String
  y     String?    @db.Char(36)
  externalId   String?
  status       SmsStatus @default(initialized)
  createdAt    DateTime  @default(now())
  updatedAt    DateTime  @updatedAt
  sentAt       DateTime?
  deliveredAt  DateTime?
  bouncedAt    DateTime?
  body         String    @db.Text
  campaignName? String
  p     String?    @db.Char(36)
  isRestricted Boolean   @default(false)
  isDeleted    Boolean   @default(false)
  deletedAt    DateTime?
}

enum SmsStatus {
  initialized
  accepted
  scheduled
  queued
  sending
  sent
  delivered
  undelivered
  failed
}

Environment & setup

  • OS: Mac OS
  • Database: MySQL
  • Node.js version: v14.16.0

Prisma Version

prisma               : 2.28.0
@prisma/client       : 2.28.0
Current platform     : darwin
Query Engine         : query-engine 89facabd0366f63911d089156a7a70125bfbcd27 (at node_modules/prisma/node_modules/@prisma/engines/query-engine-darwin)
Migration Engine     : migration-engine-cli 89facabd0366f63911d089156a7a70125bfbcd27 (at node_modules/prisma/node_modules/@prisma/engines/migration-engine-darwin)
Introspection Engine : introspection-core 89facabd0366f63911d089156a7a70125bfbcd27 (at node_modules/prisma/node_modules/@prisma/engines/introspection-engine-darwin)
Format Binary        : prisma-fmt 89facabd0366f63911d089156a7a70125bfbcd27 (at node_modules/prisma/node_modules/@prisma/engines/prisma-fmt-darwin)
Default Engines Hash : 89facabd0366f63911d089156a7a70125bfbcd27
Studio               : 0.417.0

Issue Analytics

  • State:closed
  • Created 2 years ago
  • Comments:10 (7 by maintainers)

github_iconTop GitHub Comments

2reactions
pimeyscommented, Aug 26, 2021

Reproduction:

datasource db {
  provider = "mysql"
  url      = "mysql://root:prisma@localhost:3306/prisma"
}

model A {
  id Int           @id @default(autoincrement())
  a  Int
  b  Int
  c  Int
  d  Int
  e  Int
  f  Int
  g  Int
  h  Int
  i  Int
  j  Int
}

Directly communicating with the engine using GraphQL, create one item first:

mutation {
  createOneA(
    data: { a: 1, b: 2, c: 3, d: 4, e: 5, f: 6, g: 7, h: 8, i: 9, j: 10 }
  ) {
    id
    a
    b
    c
    d
    e
    f
    g
    h
    i
    j
  }
}

Then run a few updates with the id you got back, e.g.

mutation {
  updateOneA(
    where: { id: 2 }
    data: { a: 1, b: 2, c: 3, d: 4, e: 5, f: 6, g: 7, h: 8, i: 9, j: 10 }
  ) {
    id
    a
    b
    c
    d
    e
    f
    g
    h
    i
    j
  }
}

I did two queries, resulting in two SQL statements that have the ordering wrong:

UPDATE `prisma`.`A`
SET `a` = ?,
    `f` = ?,
    `h` = ?,
    `j` = ?,
    `i` = ?,
    `c` = ?,
    `e` = ?,
    `b` = ?,
    `g` = ?,
    `d` = ?
WHERE `prisma`.`A`.`id` IN (?);

and

UPDATE `prisma`.`A`
SET `h` = ?,
    `i` = ?,
    `f` = ?,
    `j` = ?,
    `a` = ?,
    `d` = ?,
    `c` = ?,
    `b` = ?,
    `e` = ?,
    `g` = ?
WHERE `prisma`.`A`.`id` IN (?)
1reaction
thomaschaafcommented, Aug 25, 2021

@janpio do you need any more info? We are running many thousand queries / minute at finanzcheck/smava and this is problematic for us. I’d be happy to help provide more data if needed.

Read more comments on GitHub >

github_iconTop Results From Across the Web

Using Prepared Statements - JDBC Basics - Oracle Help Center
The advantage of using SQL statements that take parameters is that you can use the same statement and supply it with different values...
Read more >
PreparedStatement batching with different SQL statements
I'd like to have a prepared statement primarily for the speed, secondarily for the security. I want to be able to fill out...
Read more >
Difference Between Statement and PreparedStatement
Both Statement and PreparedStatement can be used to execute SQL queries. These interfaces look very similar.
Read more >
Using Prepared Statements
The advantage of using SQL statements that take parameters is that you can use the same statement and supply it with different values...
Read more >
Prepared Statements - Manual - PHP
The MySQL database supports prepared statements. A prepared statement or a parameterized statement is used to execute the same statement repeatedly with high ......
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found