EF Core 11 makes your split queries faster
steven-giesel.com
steven-giesel.com
Alternative query languages like EdgeQL show what first class support for nested data (and navigations) could look like, while the data model is still relational.
For example how would you use it to return a list of events and, for each event, the list of attendees in that event?
jOOQ emulates this feature for arbitrary databases and has the best explanatory article on the web about MULTISET imo
https://www.jooq.org/doc/latest/manual/sql-building/column-e...
<array aggregate function> ::= ARRAY_AGG <left paren> <value expression> [ ORDER BY <sort specification list> ] <right paren>
I hope this helps
Please enlighten me.
---
EDIT: According to LLM friends you could achieve before wire de-duplication by using FOR JSON AUTO in SQL Server or jsonb_agg in PostgreSQL. Not sure how much overhead that incurs though.
One could envision a "Cartesian product" operation in the wire protocol, but I'm not convinced that's a good approach.
> You'd still return a multiplicative amount of rows, even if those rows contained only a reference
Sure, but a pointer is still a massive win over records, and I think a further cartesian product wire protocol extension would not be worth the hassle. > `array_agg` in postgres avoids this
That one is tracked here: https://github.com/npgsql/efcore.pg/issues/2633Some kind of "product" operator on the other hand reduces the cost to additive (just like `array_agg`).
> That one is tracked here: https://github.com/npgsql/efcore.pg/issues/2633
That issue is only about supporting `array_agg` as a function on tuples, not as an implementation strategy for `Include`s of collections.
> I don't think pointers (beyond a simple "same as in previous row" marker) will be a huge improvement, since you still get a multiplicative number of rows
A marker as "byte offset in response data" is very efficient. Consider this: SELECT BlogPost bp LEFT JOIN Comment c WHERE bp.id=101 AND c.blogPostId=bp.id
If the BlogPost is 1KiB in size and has 500 comments, doing it naively will return `500 * 1KiB` for the BlogPost part.
To contrast, suppose your format needs 3 bytes for pointers, you will use `1 * 1KiB + 500 * 3B` for the BlogPost part.Compression and decompression takes CPU-time, I have a hunch this brings in an unacceptable penalty. At least this route hasn't been chosen while it would be the easiest to implement.
As far as your idea, I think where a lot of the challenge lies in that it complicates a lot of the up-front protocol.
Some of these DB protocols are downright ugly [0], and need to have a very long tail for supporting systems built on older versions. And they can be very finicky thus people are afraid to touch both the DB side and the Driver side.
So, at best you'd need to have a special connect string and then work with driver teams and/or vendors to understand the new format, deal with all of the teething issues, and will have to continue to support the old protocol in your DB code for at least another decade (probably longer for any commercial product.)
[0] - TDS comes to mind, I'm betting TTC/OPI is not fun either.
AsSingleQuery is as dangerous as this makes it sound. This works surprisingly well if you know that the number of included entities is low, but only then.
You can get much better queries here if you write a Select() and let EF Core translate that into SQL. That will probably do roughly want you are imagining here, usually with subqueries fetching the data from related entities.
The problem however is in how results are returned over the wire. Duplicating rows is needless, but seems to be still the standard.
Many of our customers routinely dealt with orders that have 10k+ lines. So if you did it all in one go, you've now turned 200 head fields into 10 million that needs to be transmitted to the client and deduplicated there.
We have the root primary key on all child tables, so we fire off a handful of queries to load the complete data set for an order. Very fast as it's all indexed of course.
Collect the data in the stored procedure with temp/in-memory tables and return minimal, non-duplicated, related result sets.
Single round trip, still accumulates results in efficient bulk batches, and allows results to be processed by the client as they stream in.
Joking (but not really) aside, EF seems to be the easiest way to shoot yourself in the foot, and write code which you think is transactional, but is not actually transactional, and would be transactional if expressed in pure SQL.
(I always upgrade projects by first upgrading the runtime and checking everything then separately (and maybe much later!) upgrading the framework.)
One of the challenges for their team I'm assuming is making sure the release notes also get copied to the actual documentation. This was one case where I thought the same thing and only until reading the release notes realized it was already a feature.