-
Notifications
You must be signed in to change notification settings - Fork 3.2k
-
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
Simple query with Include() executes 2 SQL queries instead of 1 #9987
Comments
If you have a single query SQL for above case then let us know. |
So what would be the proper syntax to get data from ApplicationUser and from NotificationsReceived in a single query? It doesn't exist? If so then it looks like a design flaw.
On a side note: how come this doesn't even give any warning? This behavior looks extremely bad. |
If you can provide single SQL query which would get all data we can look into how to write Linq query to achieve that translation or even improve query pipeline with linq query like above to generate such translation. Beyond that it is all about how & what data is stored. If the data stored does not allow single query comprehension then it may not be possible. It gives warning during query compilation phase that it would be evaluated on client. |
I see how this could be tricky. But if the count is constant (e.g. Take(5)), then it's possible I think. 1 notification: CREATE table users (id int, name text);
CREATE table notifications (id int, userId int, message text);
INSERT users values (0, 'Foo');
INSERT users values (1, 'Bar');
INSERT notifications values (0, 0, 'Hello');
INSERT notifications values (1, 0, 'Bye');
INSERT notifications values (2, 0, 'Bye2');
select (select users.name from users where users.id = 0), (select top 1 notifications.message from notifications where notifications.userId = 0) output: X notifications: CREATE table users (id int, name text);
CREATE table notifications (id int, userId int, message text);
INSERT users values (0, 'Foo');
INSERT users values (1, 'Bar');
INSERT notifications values (0, 0, 'Hello');
INSERT notifications values (1, 0, 'Bye');
INSERT notifications values (2, 0, 'Bye2');
select (select users.name from users where users.id = 0),
(select top 1 notifications.message from notifications where notifications.userId = 0),
(select top 1 z.message from (select top 2 * from notifications where notifications.userId = 0 order by notifications.id) z order by z.id desc),
(select top 1 z.message from (select top 3 * from notifications where notifications.userId = 0 order by notifications.id) z order by z.id desc) output: It just feels very hacky to have to connect to the database so many times only because there's no syntax to get the results in a single query. Connecting to database also takes time, correct? Doesn't it mean that it would be faster to execute everything in a single query (even if database would have to split it into several queries internally anyway)? |
Presently, EFCore make the argument of skip/take as parameter since same SQL can be used with just different Top/Fetch/Offset. Let's break apart the case of For
Of course, it is possible to write a single query generating above output and forming correct projection on client side. But the repetition of data on left side causes duplicated data to be fetched from server. Even though there will be single query in this case, there will be significant amount of data transferred from server (which is unnecessary). To combat with such issue, we decided to generate 2 queries (to fetch relevant data from each table separately) and combine them on client. Even though its 2 queries, it avoids duplicated data fetch. There are different cases, when one method would be faster than other but it is not possible to determine which one would be faster without doing database query. Hence on safe side, we produce 2 queries. For queries like above with Take, we are causing N+1 queries but we are trying to condense such behavior into 2 queries which is being tracked in #9282 Coming back to case of Conclusion: When looking at performance, the number of queries run against alone is not a good indicator. You also need to consider the amount of data being fetch back. Also in the context of EF, you need to consider the cost of compiling the query. Not to mention, SqlServer also catches SQL queries but for each new SQL, it also need to generate query execution plan. The best way to approach is to measure perf by running queries. |
Thank you for the detailed explanation. It definitely helped me understand how difficult it would be to implement such behavior and I agree with everything you said. However the main problem is still there, but at least I now know that it can't be solved by EntityFramework. It just feels bad that a database, which is supposed to allow fetching data, fails at its only purpose due to lacking syntax and what seems like a bad design flaw. In theory it should be possible to fetch user info + any number of notifications with:
The only thing which prevents this is syntax. Anyway, it's just some idle musing. Thanks for your help. |
This query:
Executes 2 queries which seems unnecessary
The text was updated successfully, but these errors were encountered: