You may have faced an interesting error trying to run queries in parallel with EF Core and Postgres: "A command is already in progress" which isn't very specific but refers to parallel execution failure.
This piece of code represents an intention of parallel query execution:
var city = db.Cities.ExecuteDeleteAsync();
var forecasts = db.WeatherForecasts.ExecuteDeleteAsync();
await Task.WhenAll(city, forecasts);
Seems that it should work, so what's wrong?
Let's get a little bit into the details of what's going on here.
ExecuteDeleteAsync()
runs the SQL query in DB immediately, so there is no need to call SaveChangesAsync()
. Also, EF Core doesn't track any changes as entities are not loaded into memory.
Task.WhenAll()
allows tasks to be awaited concurrently. When dealing with I/O-bound operations, such as database interactions, they are expected to be parallelized, as in our case.
Please note that city and forecast entities are not connected with a foreign key. It looks like they should be, however, for testing purposes, I intentionally avoid that. If they are connected with a foreign key and have a CASCADE restriction, then this call will work because forecasts will be deleted along with the cities.
What have we missed?
It turned out that Postgres doesn't support parallel query execution within the same connection, unlike the SQL Server.
💡Tip: The support of parallel query execution in the SQL Server is turned off by default, but it's possible to enable it with
MultipleActiveResultSets=True
.
But be careful and consider the potential risks. Ask yourself, are you sure your project needs it?
With such configuration, the code above will work.
Is there anything you could do?
Yes, you can run queries with separate db contexts, meaning queries will run on different connections. However, a more general approach is to run queries sequentially.
await db.Cities.ExecuteDeleteAsync();
await db.WeatherForecasts.ExecuteDeleteAsync();
Should you get upset because of it?
Definitely not.
❌ Parallel query execution has underlying concurrency limitations, which could lead to deadlocks or timeouts
✔️ Queries from separate connections will be executed in parallel at the I/O level, and the DB runs them in parallel, too.
Top comments (0)