In my applications users can perform actions on a few thousand aggregate root instances with a single click. The problem is that the UI is blocked for several seconds (~ 3) what feels too slow. So, I'm looking for way to improve the database operation.
The respective entity class looks (simplified) like this:
class InspectionPoint {
val id: InspectionPointId
val version: Short
val description: String
val maintenanceLevels: Set<MaintenanceLevelId>
}
The application uses JPA/Hibernate for persistence. The current behavior is that all aggregate roots are fetched from the database, updated by the application and then written back to the database with lots of update, delete, and insert statements. The flow is as follows:
- Fetch all entities (aggregate roots) from the DB
- n * update entity (increment version in this case)
- n * delete
maintenanceLevels
from collection table - n * insert
maintenanceLevels
into collection table
As you can see, there are lots of database statements.
The question is how to speed it up. Since every aggregate root carries a version
attribute for optimistic concurrency control, it wouldn't be possible to just manipulate the collection table. But maybe this flow would work:
Performing updates without loading entities
- update all
InspectionPoint
rows with the given IDs directly in the database (increment version) - insert or delete rows in the collection table for
maintenanceLevels
, what would require to distinguish both operation in the client, public (HTTP) API, and in the application service.
The main disadvantages are:
- client, HTTP service, application service needs to be modified
- domain logic in the entities gets completely bypassed
- custom SQL is required what requires some work and makes maintenance harder
Although the performance should be pretty good, there are some severe disadvantages, too.
Do you have any other suggestion how to solve aggregate root bulk updates?
The problem is that the UI is blocked for several seconds (~ 3) what feels too slow
. Then don't block it, make it asynchronous. If concurrency is a problem, enqueue the requests, set limits, make everything happen on the background and let the user to move forward or just wait.