-
Notifications
You must be signed in to change notification settings - Fork 3.2k
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
Batch execution of multiple ExecuteUpdate / ExecuteDelete / ExecuteSql #33143
Comments
Duplicate of #10879 |
Although #10879 discusses allowing batching queries, ExecuteUpdate/ExecuteDelete are implemented via the EF query pipeilne and would very likely be part of that issue.
I imagine your actual scenario is more complex, but this sounds like something that's better handled by cascade deletes in the database. I agree that batching updates/deletes is definitely useful and should be implemented, but it's also better to let the database take care of cascades whenever that's possible.
The problem here is mainly an API issue - ToQueryString() currently works over IQueryable, and ExecuteUpdate/Delete don't expose one, but rather execute. The same problem exists with terminating querying operators such as Max/Sum. Having a ToQueryString variant which accepts the query as an argument (i.e. |
I understand. That's why I suggested an API to create a As far as #10879, I think it's different because it is about issuing multiple queries with readers. This is complicated because multiple results sets need to be handled. The batching AP I'm proposing above only processes non-reader statements which are executed via Because of this difference, I think it would be much easier to implement because there are no results sets to manage. |
Good point @ajcvickers |
Not really - both queries and ExecuteUpdate/Delete are actually quite similar under the hood. In any case, the important thing here isn't the implementation details, but rather the user API we'd expose for batching; and from a user perspective, there's very little different between e.g. ExecuteDelete() and Max() as terminating operators - both return a single int, so the API for batching them can be the same. The fact that under the hood the former is invoked via DbCommand.ExecuteNonQuery() and the latter via ExecuteReader() (or possibly via ExecuteScalar()) is unimportant for the user-facing API.
I'd suggest spending some time looking at the implementation - that should make you a bit more familiar with the internals. |
I was checking out |
Happy you like it! Yeah, it's an important step forward - we'll need to start using that in EF at some point too. In any case, I'll go ahead and close this issue as a duplicate of #10879, as discussed above. |
Problem:
We try to use EF as much as possible for all interactions with SQL server, using strongly typed queries and the change tracker. Because of all the benefits that this provides in terms of maintenance, parameterization, etc...
However, there are still many places in our codebase where we have to resort to building sql commands manually by concatenating strings and issuing commands manually. For virtually all of these cases, this is because we need to do bulk deletes and updates.
EF 7 introduced
ExecuteUpdate
andExecuteDelete
and we have been trying to use these instead of building sql commands manually.Unfortunately we have run into some performance concerns.
It's very often the case that we need to issue multiple commands at a time. For example, if a root object is deleted, we issue several bulk delete commands to delete all its related children objects. As a (fictitious) example, if a customer is deleted, we might issue commands to delete all of their orders, all their fulfilments, etc... (in this particular example, we'd probably want to keep these objects but in our domain, we don't). As single root object deletion can often result in 5+ separate bulk delete commands to delete all related objects.
For performance reasons, we issue a single batch of SQL which contain all the commands.
Unfortunately, batching doesn't seem to be possible with ExecuteUpdate / ExecuteDelete / ExecuteSql, hence why we can't use them for now.
See https://learn.microsoft.com/en-us/ef/core/saving/execute-insert-update-delete#change-tracking
As of today, the recommend solution is to create a transaction to wrap all commands. Something like this:
The problem is that a separate roundtrip is necessary for each ExecuteDelete/ExecuteUpdate. For us, this matters a lot.
My feature request would be to be able to batch multiple ExecuteUpdate / ExecuteDelete / ExecuteSql into a single SQL batch to sql server.
Proposed solution:
The idea is to be able to create delete/update/sql statements, without executing them immediately.
Example:
Side notes:
For example, right now we can't use ToQueryString() with ExecuteDelete/ExecuteUpdate. If we can create statements as above, maybe they could also support
ToQueryString
, which we find very useful for logging, debugging and other diagnostics.SaveChanges
. It would even better if we could run both in a single call such asawait context.RunStatementsThenSaveChangesAsync(statement1, statement2, ....)
.I would love to hear your thoughts.
The text was updated successfully, but these errors were encountered: