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

Unit of Work calculates unnecessary UPDATE queries for enum properties in cascaded collections #10125

Closed
mbabker opened this issue Oct 12, 2022 · 3 comments

Comments

@mbabker
Copy link
Contributor

mbabker commented Oct 12, 2022

Bug Report

Q A
BC Break no
Version 2.13.3

Summary

While troubleshooting performance issues in one of our Symfony 6.1 applications, we found a request where a large number of UPDATE queries were being made which were generally unrelated to the actual request, screenshot is from New Relic:

enum-updates-gone-awry

Except for the time_sold column (unrelated to this bug report, it's something I still need to debug), all of the changes in the UPDATE statements are touching columns that use backed enums in their mapping.

After debugging, I've found that this happens when persisting an entity that includes a "cascade persist" on a collection. When the unit of work calculates the change set with one of these entities loaded, it's computing the following change for one of these enum fields:

  [338] =>
  array(1) {
    'status' =>
    array(2) {
      [0] =>
      enum App\LotStatus::AVAILABLE : string("available");
      [1] =>
      string(9) "available"
    }
  }

Current behavior

Unit of Work calculates incorrect changes, causing unnecessary UPDATE statements during a transaction

How to reproduce

https://github.com/mbabker/enum-uow-bug includes the minimal reproducer I was able to build to represent this issue.

Ensuring you have sqlite available on your system, clone the repo and run the following commands:

php app.php orm:schema-tool:create
php app.php orm:schema-tool:update --force
php app.php app:seed-database
php app.php app:update-auction-name --auction-id=1 --name="Changed Name"

When the last command runs, it'll dump out the computed change set from the Unit of Work as well as the log records from the middleware:

array(3) {
  [342] =>
  array(3) {
    'name' =>
    array(2) {
      [0] =>
      string(13) "Testing Event"
      [1] =>
      string(12) "Changed Name"
    }
    'type' =>
    array(2) {
      [0] =>
      enum App\AuctionType::LIVE : string("live");
      [1] =>
      string(4) "live"
    }
    'status' =>
    array(2) {
      [0] =>
      enum App\AuctionStatus::ACTIVE : string("active");
      [1] =>
      string(6) "active"
    }
  }
  [338] =>
  array(1) {
    'status' =>
    array(2) {
      [0] =>
      enum App\LotStatus::AVAILABLE : string("available");
      [1] =>
      string(9) "available"
    }
  }
  [336] =>
  array(1) {
    'status' =>
    array(2) {
      [0] =>
      enum App\LotStatus::AVAILABLE : string("available");
      [1] =>
      string(9) "available"
    }
  }
}
DBAL Log Entries:
 * Connecting with parameters array{"driver":"pdo_sqlite","path":"/Volumes/Samsung T7/Sites/enum-uow-bug/db.sqlite"}
 * Executing statement: SELECT a0_.id AS id_0, a0_.name AS name_1, a0_.type AS type_2, a0_.status AS status_3, l1_.id AS id_4, l1_.number AS number_5, l1_.title AS title_6, l1_.status AS status_7, l1_.auction_id AS auction_id_8 FROM Auction a0_ LEFT JOIN Lot l1_ ON a0_.id = l1_.auction_id WHERE a0_.id = ? (parameters: array{"1":"1"}, types: array{"1":2})
 * Beginning transaction
 * Executing statement: UPDATE Auction SET name = ?, type = ?, status = ? WHERE id = ? (parameters: array{"1":"Changed Name","2":"live","3":"active","4":1}, types: array{"1":2,"2":2,"3":2,"4":1})
 * Executing statement: UPDATE Lot SET status = ? WHERE id = ? (parameters: array{"1":"available","2":1}, types: array{"1":2,"2":1})
 * Executing statement: UPDATE Lot SET status = ? WHERE id = ? (parameters: array{"1":"available","2":2}, types: array{"1":2,"2":1})
 * Committing transaction

Expected behavior

Changes aren't detected for unchanged enum properties, the above reproducer should have the following log output:

DBAL Log Entries:
 * Connecting with parameters array{"driver":"pdo_sqlite","path":"/Volumes/Samsung T7/Sites/enum-uow-bug/db.sqlite"}
 * Executing statement: SELECT a0_.id AS id_0, a0_.name AS name_1, a0_.type AS type_2, a0_.status AS status_3, l1_.id AS id_4, l1_.number AS number_5, l1_.title AS title_6, l1_.status AS status_7, l1_.auction_id AS auction_id_8 FROM Auction a0_ LEFT JOIN Lot l1_ ON a0_.id = l1_.auction_id WHERE a0_.id = ? (parameters: array{"1":"1"}, types: array{"1":2})
 * Beginning transaction
 * Executing statement: UPDATE Auction SET name = ? WHERE id = ? (parameters: array{"1":"Changed Name","2":1}, types: array{"1":2,"2":1})
 * Committing transaction
@W0rma
Copy link
Contributor

W0rma commented Oct 13, 2022

Could that be related to #10088 ?

@mbabker
Copy link
Contributor Author

mbabker commented Oct 13, 2022

Possibly related, but I patched my repro locally and it's still giving the extra UPDATE queries with it applied.

@mbabker
Copy link
Contributor Author

mbabker commented Nov 23, 2022

Looks to be fixed on current 2.13 dev build.

@mbabker mbabker closed this as completed Nov 23, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants