The JADE 2022 release meets tomorrow’s business demands.
the JoobCollection base class doesn't implement the IEnumerable/IQueryable method .Any()
. That means it's left to the default implementation, which means we read all the items in the collection from the database to check whether there are any items in the table - a potentially very expensive operation that has a very cheap workaround. We measured that even if we were to only attempt to read the first item in the DB each time, it's still an order of magnitude faster to use the Count
property (30ms vs 5ms)
Because using System.Linq
is so ubiquitous, it's not practical for us to write an extension method, so we need an implementation that's "closer" in .NET terms.
This is entirely a developer productivity problem:
1) It's not always clear that the particular method we're in is operating on a JadeCollection (i.e. we depend on interfaces like IEnumerable
) unless we start attempting to hold a lot more context in our heads.
2) The Linq methods are so common and helpful, they exist in our code even when we're not operating on a JadeCollection - their existence doesn't raise eyebrows for a reviewer.
3) There is a strong preference by the .NET community and all the static checkers built for it (like ReSharper) encourage the use of .Any()
over .Count() > 0
because of the performance improvements available - JADE is asking us to go against the flow on all that experience / peer pressure.
4) It doesn't make a noticeable difference when the collection is small and our test data often is.
So what's the impact for our customers?
Performance regressions are often only found when we hit production, purely because it's really difficult to produce test data that is large and varied enough to find that kind issue.
Not seeing this with Dotnet 9, J 22 Ansi. Calls to Any and Count both map to RootSchema::Collection::size
I suspect you're using an older version of Dotnet (before dotnet 6?)
LINQs extension methods for Count and Any had the common problem of enumerating to resolve the count if it was over an I/Enumerable, because there's no count property on there.
This was a common with SQL & Dotnet web dev as well.
JoobCollection implements all this:
public abstract class JoobCollection<T> : JoobObject, IJoobCollection<T>, ICollection<T>, IEnumerable<T>, IEnumerable, IJoobCollection where T : JoobObject
ICollection has a Count property.
Later versions of DotNet and LINQ address this - LINQ checks to see if the collection is actually some kind of list or collection first, which then lets it delegate to the Count property, and avoid enumeration. The source is online and publicly available.
I've attached my own code sample, which produces the attached profiler report - no enumeration.
Output:
Hello, World!
True
18846
The problem is likely with how you're using Dotnet and LINQ, what version they're on, and probably not Jade.
If a DotNet version upgrade is too difficult (Though I would definitely recommend, since you are chasing after performance) you can try changing usages of IEnumerable<T> to ICollection<T>, or try using IQueryables instead if your Jade collections are MKDs, as a fix in the meantime.
Can you confirm Dotnet version details and provide code samples with profiler results?
Corrected Count >> Any
Oh dear, it's clearly Monday - I meant
.Any()
and kept insisting on calling it `.Count()`