SingleOrDefault or FirstOrDefault? When LINQ might harm you

  Рет қаралды 50,342

Nick Chapsas

Nick Chapsas

Күн бұрын

Check out my courses: dometrain.com
Become a Patreon and get source code access: / nickchapsas
Hello everybody I'm Nick and in this video I will explain how First, FirstOrDefault, Single and SingleOrDefault LINQ methods work and why you might not be using the one you should be using.
Workshops
NDC Oslo | 26 - 30 Sept | bit.ly/ndcoslo2022workshop
NDC Sydney | 10 - 14 Oct | bit.ly/ndcsydney2022workshop
dotnetdays | 20 - 22 Oct | bit.ly/dotnetdays2022workshop
NDC Minnesota | 15 - 18 Nov | bit.ly/ndcminnesota2022workshop
NDC London | 23-27 January 2023 | bit.ly/ndclondon2023
Timestamps
How Single, SingleOrDefault, First, FirstOrDefault work - 0:00
Why is this difference in logic important? - 3:47
Creating and running the benchmarks - 6:01
What can we make of all this? - 11:14
Don't forget to comment, like and subscribe :)
Social Media:
Follow me on GitHub: bit.ly/ChapsasGitHub
Follow me on Twitter: bit.ly/ChapsasTwitter
Connect on LinkedIn: bit.ly/ChapsasLinkedIn
Keep coding merch: keepcoding.shop
#csharp #dotnet #linq

Пікірлер: 234
@chezchezchezchez
@chezchezchezchez Жыл бұрын
just learned you can add a default overload! Thanks!
@nanvlad
@nanvlad Жыл бұрын
@@AlbertoMonteiro In previous versions you can do .DefaultIfEmpty(obj).First()
@iOLlVER
@iOLlVER Жыл бұрын
Great Video!, The same applies to Count(x => x == 1) > 0 vs. Any(x => x == 1). Rider also suggests to refactor Count() > 0 to Any()
@iOLlVER
@iOLlVER Жыл бұрын
Actually (correct me if I am wrong) in a EF context, using Any() is even superior to FistOrDefault() != null because FirstOrDefault() has to query all columns and do the deserialization.
@vladyslavhrehul2185
@vladyslavhrehul2185 Жыл бұрын
Count is faster on List and Any is faster on IEnumerable
@rhoonah5849
@rhoonah5849 Жыл бұрын
@@vladyslavhrehul2185 That's because a List has a property called Count that store the value where IEnumerable has a method called Count() that iterates the rows in order to count them so your comparison is a property versus a method.
@rhoonah5849
@rhoonah5849 Жыл бұрын
@@iOLlVER Using Any() is always faster since it doesn't iterate over the enumeration.
@pg_pete
@pg_pete Жыл бұрын
@@vladyslavhrehul2185 Count, full stop, isn't an operation, it's a property (like Length on an array), so it's a bit of an unfair comparison. Any() will be faster than Count() > 0 in all cases, although I wouldn't know an Oracle Optimizer would execute your SQL'ed lambda-expression.
@nickandrews1985
@nickandrews1985 Жыл бұрын
Great content. I appreciate the videos on the latest and greatest features as well, but I would love to see more like this.
@milanmladenovic
@milanmladenovic Жыл бұрын
Thank you Nick, great video as always.
@mangoaaron3146
@mangoaaron3146 Жыл бұрын
Updating my code again after another video. Thanks Nick!
@brianm1864
@brianm1864 Жыл бұрын
You are the man Nick! Great video!!
@mattcredland3166
@mattcredland3166 Жыл бұрын
Love the videos keep it up! I would be interested to see some Rider tips and tricks and strengths/weaknesses compares to visual studio 2022 if you get to it 😀
@JOHNDATGOONV2
@JOHNDATGOONV2 Жыл бұрын
Great video! I tend to use Single when querying EF at work where we have huge data sets and I never considered this.
@MoireFly
@MoireFly Жыл бұрын
Usually, Single is practically just as fast because you have the right indexes. And when you don't, First is usually wrong, because it's non-deterministic. You're almost always better off using Single.
@discipuloschristi6787
@discipuloschristi6787 Жыл бұрын
Personally I always ensure a unique constraint in the column definition for such cases. You should be doing that anyway, to ensure data integrity.
@MoireFly
@MoireFly Жыл бұрын
...but if you have such a constraint, the perf difference should be negligible. I can't really imagine a reasonable scenario where First makes significant gains, and is actually unproblematic.
@MarcLucksch
@MarcLucksch Жыл бұрын
Sure, a single table can have a unique constraint easily. But when you are joining a lot of crap in a view, single becomes a lot more important
@leashr
@leashr Жыл бұрын
Thanks for the explanation! Refactored all my .SingleOrDefaultAsync database LINQ queries! I often encounter "long running requests", for example, Razor Pages on first database call. But also on my API.
@battarro
@battarro Жыл бұрын
You shouldn't do that. Index your database properly, that is what your problem is. A TOP1 vs a TOP2 is negligible at the database level on an indexed column.
@uffethorsen6502
@uffethorsen6502 Жыл бұрын
Nitpick: It will not be “exponentially slower”, asymptotically it will have the same worst case behavior, but best case is much better, and average better by a factor of 2.
@pagorbunov
@pagorbunov Жыл бұрын
Sas Nickchap is my choice!
@stevepy6758
@stevepy6758 Жыл бұрын
From memory, EF will use a TOP(2) with Single. First isn't safe without assuming unique, if not it should also always be accompanied with an OrderBy clause if you cannot assume uniqueness.
@nickchapsas
@nickchapsas Жыл бұрын
As mentioned in the video, for you to be able to reap the benefits of First uniqueness need to be enforced on a different level (Insert, constraints etc)
@davidmartensson273
@davidmartensson273 Жыл бұрын
Top 2 can still be safe IF you add a where for the match. If that returns 2 items its not unique, it should always return only one line to be true. But that would still have the DB do the processing of the whole dataset, but hopefully hitting only indexes.
@andreybiryulin7207
@andreybiryulin7207 Жыл бұрын
@@davidmartensson273 Generally in MS SQL TOP 2 by index is almost as performant as TOP 1. There is very negligible difference.
@davidmartensson273
@davidmartensson273 Жыл бұрын
​@@andreybiryulin7207 Yes, I think I actually miss read the Steve Py comment so disregard my comment ;). In later comments I explain that a DB design that needs Single is in my opinion a bad design, if you need uniqueness it should be enforced when adding to the database, not when reading, so that you trap the error when its committed and in the best case can report it back to what ever source you got it from. And if you actually do not know this when accepting data I would probably add some intermediate processing and a secondary table with a uniqueness constraint to solve this. I have actually had similar cases where we needed one column to be unique for some rows but not for others, and we solved it with SQL constraints, so we never had to consider it when reading :)
@DryBones111
@DryBones111 Жыл бұрын
​@@davidmartensson273 this makes sense. Also consider, if you were to use Single, how would you realistically recover from the exception at read time? The ship to properly resolve it has already sailed at write time.
@longuinni
@longuinni Жыл бұрын
Great video Nick. SemaphoreSlim and Channels could be a good topic to cover.
@nickchapsas
@nickchapsas Жыл бұрын
I have a SemaphoreSlim video in the backlog I just need to find the perfect example for the video
@verdurakh
@verdurakh Жыл бұрын
@@nickchapsas when handling a api accept_token that you want to refresh and don't want all methods to refresh it at the same time might be a good idea
@modernkennnern
@modernkennnern Жыл бұрын
I don't think I've ever used the `Single` methods before. I know of them obviously, but I'm yet to encounter a logical use case for it
@SelmirAljic
@SelmirAljic Жыл бұрын
Lets say you have something like this: public IObservable Create(“honda”); If you use Single you wil get an exception if there are more than 1 factories returned, using First would potentially hide an underlying defect
@OhhCrapGuy
@OhhCrapGuy Жыл бұрын
If there's supposed to be only one item, you should never use .First(). Let's say you have a couple different indexes on a table, and one query uses one index and a different query uses a different index, and one index is ordered by a column in a different direction from the other, .First() is going to give you a different item for one query than for the other query. There are times where it's fine to just use .First(), but you have to be absolutely certain that there's no way for there to be a second one. Or if you know there are multiple and you just don't care which one you get. Because there's no guarantee that IEnumerable enumerate the collection in the same order every time.
@JetsetDruid
@JetsetDruid Жыл бұрын
@@OhhCrapGuy seems like you could resolve those two issues with an OrderBy.
@JetsetDruid
@JetsetDruid Жыл бұрын
@@SelmirAljic I've not used IObservable before but can you not constraint the "create" to be unique by checking first if there is already any item named "honda". Seems to me trying to enforce uniqueness after populating data is too late
@OhhCrapGuy
@OhhCrapGuy Жыл бұрын
@@JetsetDruid Why is there an additional entry in your enumerable that you never access? Hiding that problem with OrderBy is just hiding a bug that's gonna bite you in the ass later. You should only use First() when you're logically guaranteed that only one item is in the enumerable that matches your predicate.
@DanFlakes
@DanFlakes Жыл бұрын
I had the exact same thought a few hours ago. Almost as if you read my mind 😅
@kylekeenan3485
@kylekeenan3485 Жыл бұрын
Thanks for the content Nick, little topics like this are really valuable. I have always used .FirstOrDefault() as instructed when I first got into programming, however videos like this really help give a good understanding as to why! You continue to expand my mind.
@michaelsutherland5848
@michaelsutherland5848 Жыл бұрын
Great video. When can we get a guest appearance from Chap Nicksas?
@nickchapsas
@nickchapsas Жыл бұрын
Wait till I invite Napsas Chack
@a7medmahdi931
@a7medmahdi931 Жыл бұрын
We need more about linq please
@verdurakh
@verdurakh Жыл бұрын
My biggest take from this is the FirstOrDefault overload! :o
@amirdar
@amirdar Жыл бұрын
Great video as always! one thing that doesn't work for me is sending a default value as a parameter to the FirstOrDefault method (like you did with "N/A") is this a c# 10 feature?
@BigKevSexyMan
@BigKevSexyMan Жыл бұрын
While I don't think it would change the conclusion of the video, I am curious what the performance differences would be when checking a column that is properly indexed.
@JasonKaler
@JasonKaler Жыл бұрын
first does a select top 1 and single does select top 2 - so single will still be slower, especially with the impact on the database
@battarro
@battarro Жыл бұрын
Negligible. I ran the tests with a 500k rows, on an indexed nvarchar column, and the difference was 10 micro seconds at worse.
@michaelganzer3684
@michaelganzer3684 Жыл бұрын
There is probably too little real prestige in comparing a single call using method a to a single call using method b. In real scenarios, you want to optimize your queries for all the vectors. Then, how about using a grouped lookup in comparison? Group once, lookup once, benefit from knowing the amount of results plus the results, no matter the amount of queries. Surely, crossing boundaries like LINQ2SQL is another topic. I'd so much like to see whether you give it a try. :)
@robopzijnwerk5999
@robopzijnwerk5999 Жыл бұрын
Do you know if EF takes a unique index into account when creating a query for a single statement?
@yzraeu
@yzraeu Жыл бұрын
Video gets nice @ 8:14
Жыл бұрын
First() might need a order by... and Single() might not make sense without a discreet or group by. The important part is to think about what you are trying to achieve, rather than just doing what you usually do.
@paulmouatib9999
@paulmouatib9999 Жыл бұрын
Great video as always. What is this framework you use to generate your data? Faker
@nickchapsas
@nickchapsas Жыл бұрын
It's called Bogus. I have a video on it: kzbin.info/www/bejne/imrTqHhnfKallbc
@paulmouatib9999
@paulmouatib9999 Жыл бұрын
@@nickchapsas Thank you, you're the best 🦾
@calvinwilson3617
@calvinwilson3617 Жыл бұрын
Interesting, i never considered that .SingleOrDefault requires checking the whole dataset. As I understand it basically you should only use SingleOrDefault if it is POSSIBLE for the dataset being queried to have multiple matches. If it is not possible for the dataset to return multiple matches you should always use FirstOrDefault This actually makes it alot easier to choose which one to use IMO
@oM1naE
@oM1naE Жыл бұрын
If the column is indexed (and when you have use-cases where you need FirstOrDefault or SingleOrDefault it most likely should be) there is no "checking the whole dataset" involved. I still think SingleOrDefault is better if the data model / use case matches.
@lukewebber5562
@lukewebber5562 Жыл бұрын
Really the other way around. If it's possible to have multiple matches, use FirstOrDefault, or you'll get an exception. SingleOrDefault? Yeah, don't use that, except possibly to check for uniqueness on input, and always catch the exception.
@MoireFly
@MoireFly Жыл бұрын
This video is dangerous advice; avoid First(OrDefault) always. The cases when First are significantly faster are exceptionally rare in practice - and when they do occur, usually First is semantically _wrong!_ Almost all cases people say First, they're _assuming_ there's one match, and when there are multiple, you're much better served by failing fast with an exception than performance-optimizing returning the wrong result. There are potential exceptions such as when you have a total order and want the first in that order - but those are best served by MinBy or MaxBy, so even there First isn't useful.
@AlanDarkworld
@AlanDarkworld Жыл бұрын
Good video as always, just a few additional remarks: - when using first() and you are not 100% sure that there can be only one result, try to at least ensure that the collection is sorted in a deterministic fashion. Otherwise, multiple runs will produce different results, and that's a horrible place to be. - Single() is most useful to extract the single value of a colltection which you previously checked to have a count of exactly 1. First() would obviously work here as well, but I find single() to better convey the idea.
@nickchapsas
@nickchapsas Жыл бұрын
Ordering defeats the purpose. Order doesn't matter when you are querying data that shouldn't have duplicates. If there are duplicates then you have a data integrity issue in your system and your querying isn't responsible for finding it. If you assume uniqueness then first should be used over single
@AlanDarkworld
@AlanDarkworld Жыл бұрын
@@nickchapsas for in-memory, I agree. No point in saving performance by using first() if you sort the collection beforehand. But if the data is coming from a database, maybe a NoSql DB or a distributed system where the costraint can't be enforced, you can at least try to make your query somewhat more resilient by using first() over single() - but you'll need an ordering for consistent results, which can be provided without in-memory sorting e.g. by using an index. It's "pick your poison". Would you prefer to fail immediately (single) or let it continue to run (first).
@nickchapsas
@nickchapsas Жыл бұрын
@@AlanDarkworld That's even worse. NoSQL databases are partitioned so things like ordering a dataset or having single will actually cross partition can the whole database and kill your performance completely. With proper data modeling you will never have that issue
@nothingisreal6345
@nothingisreal6345 Жыл бұрын
Single = I want to make sure it is only ONE item. Zero or more than one - that's an error. If wonder why they added the overloaded versions with the predicate. For predicates we already have Where(...) and that is expressive and clear. First(x=>...) - what is it? You have to look at the name of the parameter to find out - its a predicate.
@nielsterheijden1486
@nielsterheijden1486 Жыл бұрын
Where will go through the entire dataset. The first with predicate will stop on hit.
@der.Schtefan
@der.Schtefan Жыл бұрын
It took me a long time to understand that there is nothing wrong with being Single()!
@efimov90
@efimov90 Жыл бұрын
Nick Chapsas, ok but what about Find for id? It's reasonable not to use SingleOrDefault for check id by performance, but isn't Find - the right option? And what with LinqToSql?
@nickchapsas
@nickchapsas Жыл бұрын
Find is the same as FirstOrDefault
@luvincste
@luvincste Жыл бұрын
i don't know, it's a kinda random approach; i would have made sure to separate the discourse for linq and for the linq expressions used in ef, because here you are using just an array; i mean i get that videos should be short or fewer people would watch it, but there's not only other types of collections (ie sorted list) on which you can use linq, but the DbSet too, and that's pretty common
@nickchapsas
@nickchapsas Жыл бұрын
I explained in the video how EF is different and what query it will generate
@stephajn
@stephajn Жыл бұрын
Entity Framework doesn’t need to query the whole table etc when using SingleOrDefault. It outputs a “SELECT TOP 2” query. If it finds two matches, then it throws. It does not need to enumerate the whole table. Maybe that’s not the case in other providers besides SQL Server, but that is literally what it does against SQL databases.
@leolombardi
@leolombardi 9 ай бұрын
In the worst case scenario (there is only one matching element), it does have to enumerate the whole table.
@mihaimyh
@mihaimyh Жыл бұрын
What is the difference between ordinal ignore case and invariant ignore case and when can we use one over the other?
@battarro
@battarro Жыл бұрын
Do not use InvariantCultureIgnorecase. for example what goes first á or a , or the Swedish å and the US a. InvariantCulture will treat all those as not "a", when in reality they are all "a"
@battarro
@battarro Жыл бұрын
this is from the Microsoft website: Avoid the following practices when you compare strings: Do not use string operations based on StringComparison.InvariantCulture in most cases. One of the few exceptions is when you are persisting linguistically meaningful but culturally agnostic data.
@marcotroster8247
@marcotroster8247 Жыл бұрын
What about a cached hash set for the O(1) flex instead of iterating the list like a fool? xD Database engineers invented indices for a reason. Why not let the database do the heavy lifting? :D
@tarekel-shahawy891
@tarekel-shahawy891 Жыл бұрын
Great effort, Imma stick to FirstOrDefault though
@nickchapsas
@nickchapsas Жыл бұрын
Well that's what the video was about
@yossisternlicht21
@yossisternlicht21 Жыл бұрын
Why when searching for the last Id, is Single slightly faster than First? Or is that random?
@nickchapsas
@nickchapsas Жыл бұрын
It's within marging of error because the dataset is big. It's between run to run variance but in reality it's the same
@lukewebber5562
@lukewebber5562 Жыл бұрын
I recently worked in an API that was riddled with SingleOrDefault calls, frequently without exception handling. It seems that the developers took the view that "there should only be one of these, so SingleOrDefault it is". But sometime, due to a questionable ETL script or whatever, that assumption proved to be incorrect and boom. Personally, I never use Single or SingleOrDefault, because imposing those limitations is something that should happen on input, or possibly via a unique constraint in the database.
@DaveRogersEsq
@DaveRogersEsq Жыл бұрын
I'm the opposite. I use SingleOrDefault where I expect there to be only 1. I handle the "OrDefault" scenario (as always and as you would with First). Using First, where there should be only 1, often hides a problem. If Single throws an exception, where there should be only 1, you have a data problem which can quickly be identified by good logging and exception notification code. Then you can launch an investigation as to how the data got corrupted. Probably a lack of business validation, or some data mutation code was not atomic. I'd rather go through that path, rather than have First hiding a problem which could go unnoticed for a long time because ... First.
@pedersenlasse
@pedersenlasse Жыл бұрын
I wonder what Chap Nicksas thinks about this.
@Galakyllz
@Galakyllz Жыл бұрын
I regularly fight to get my coworkers to use "Single" and "SingleOrDefault" because if there is more than one of a thing (when there should only be one thing), then it demonstrates that there's a problem in the database/upstream. I get constant push back saying "Well, the database tables permit duplicates but it will never happen." That phrase "it will never happen" is the biggest lie you will ever hear. Using the appropriate filter method consistently safeguards your code against bad data elsewhere in your system and you will find these errors immediately instead of months later when some serious damage has already been done.
@nickchapsas
@nickchapsas Жыл бұрын
Your coworkers are right. Think about it. Is it the responsibility of your queries to detect data integrity issues with your data layer. Ofc not, that’s a write/update concern.
@Galakyllz
@Galakyllz Жыл бұрын
@@nickchapsas I wish I worked in the environment that you work in where you have good controls around data integrity and your coworkers actually care about that. When you have different coworkers of different skill levels making changes to different parts of the larger machine, having safeguards at all levels of the system is essential. The database _should_ care about uniqueness if it's supposed to be a unique column, but that's not always the case and pretending like it just-so-happens to be unique because the interface doesn't (currently) permit it *always* bites you when someone else makes a change somewhere unexpected for their own use case. tl;dr; my coworkers are wrong because our database is wrong. Thanks for your video and reply, btw. I couldn't hit Subscribe fast enough.
@Galakyllz
@Galakyllz Жыл бұрын
@@nickchapsas Reply #2 I'll give you a paraphrased, badly designed, but informative use case, if you think that I'm still mistaken. The interface ultimately saves a user with name and email, the email is separated out into a separate table for our purposes. The email should be unique, the save function makes sure of that upon save, but the database permits non-unique email addresses. The SendEmailToUsers application-level function ultimately pulls out all users from the database with the goal of sending an email to each user. It iterates over every user, pulling back their single email address by calling the GetEmailOfUser method in our repository class. The repository layer's function GetEmailOfUser is supposed to return a single email address, but two could be returned from the stored procedure call since the database technically permits that data state. Why would I *not* want to have a "Single" right here? Why is "First" better?
@donr484
@donr484 Жыл бұрын
I was thinking to myself that Microsoft had to build in a check when each result of .Single() is found to throw an exception immediately at the second item. If not, it would iterate the entire collection, then see there was more than one and throw an exception, which would result the worst possible performance. I checked the reference source. When there is no predicate, it looks good. If the collection can be converted to a list, it checks the count first. If the collection cannot be converted to a list (therefore it doesn't have a .Count property), it fails as soon as it tries to move to a second result. However, the predicate version is much worse! It is actually iterating the entire collection, then checking the count of all results after that! If they added a test for count > 1 right after incrementing count++ and exit the loop, it could save countless iterations! (EDIT: I was looking at .NET Framework 4.8 reference source. It is fixed in the latest .NET source and more efficient.)
@pwn2own23
@pwn2own23 Жыл бұрын
How is Single() implemented, when using IQueryable with EF?
@nickchapsas
@nickchapsas Жыл бұрын
I haven't tried to see the query generated but I would assume it add a Top 2 in the query which will probably lead to a full scan if you only have one item. Haven't tried it however since I don't use EF so you might wanna give it a go and see
@maskettaman1488
@maskettaman1488 Жыл бұрын
@@nickchapsas TOP 2 is exactly what EF/SqlServer 6.0 does
@johns193
@johns193 Жыл бұрын
Last
@danielschmid8530
@danielschmid8530 Жыл бұрын
I never had a reason to use Single just because I don't see a use case. When I only want the first of something I'll use FirstOrDefault, and when I need to make sure that only one of this exists I'll validate using Count(). I'm not using huge data sets so this is perfectly fine for me. I don't see why Single even exists especially when you shouldn't provoke exceptions.
@SimonClarkstone
@SimonClarkstone Жыл бұрын
What if you want to get the only item that satisfies a predicate, and check the precondition that there is only one item that satisfies that predicate? When using Java I kept reinventing Single myself, especially in tests, so it's nice to have it as a built-in in C#.
@JadveiTTI
@JadveiTTI Жыл бұрын
When you are using Count you executing query twice (one for count, one for result) and with single you can do it with one query
@davidmartensson273
@davidmartensson273 Жыл бұрын
@@SimonClarkstone In tests the testing framework usually have a specific test for single than not only makes the assurance but actually out of the box provides good explanations for when it fails.
@davidmartensson273
@davidmartensson273 Жыл бұрын
@@SimonClarkstone I any case where I have had to ensure singularity its either a database where I can use a unique index (much safer than trusting every case where you ad things) or like a dictionary that also fails if you try to add duplicates. Its safer, catching the problem on addition instead of consumption. Sure, there could be a case where you might allow for some duplicates but not for others, but in that case I would still try to enforce it in the storage to catch it on addition.
@SimonClarkstone
@SimonClarkstone Жыл бұрын
@@davidmartensson273 Those do apply in many cases, yeah. I do like how C# dictionaries make it easier to detect collisions rather than silently overwriting. I've recently been writing some parsers for input that could be poorly formatted, which needs to be matched up to existing data that it might not match, and Single was well-suited to some of the tasks.
@serb1146
@serb1146 Жыл бұрын
Great Video!, Thanks Nick. Again 69 :) Maestro!
@user-wu2dj6gn7l
@user-wu2dj6gn7l 8 ай бұрын
It's a whole different ball game with the data is in a relational database that may or may not have indexes and may or may not be clustered
@JoeStevens
@JoeStevens Жыл бұрын
I've been getting my team away from using First() to always using FirstOrDefault() and handling the null case. The "Sequence contains no elements" error can be hard to debug when you have a bunch of First() calls in the constructor for a DTO and you don't know which one failed. When you check for null after the call to FirstOrDefault() you can then create a more meaningful error message.
@alexbarac
@alexbarac Жыл бұрын
I was wondering why the constructor is the where you are using any amount of First or FirstOrDefault, it's not really what the purpose of the constructor is, to have collections being iterated through inside it?
@JoeStevens
@JoeStevens Жыл бұрын
@@alexbarac You are building a smaller data object from a larger set so you only want a subset of the lists inside your new object. Since it's a DTO it's a dumb object with no logic inside of it. So you don't filter inside the DTO. You filter in the provider that is building it.
@JoeStevens
@JoeStevens Жыл бұрын
Even if you filtered into local variables you can have multiple lists getting filters on lines right next to each other. Since sometimes the line number on the stacktrace is of by one or two or can be hard to know which one failed. The big win is that the error messages you can surface can be unique for you application and help the users or devs solve the problem quicker.
@alexbarac
@alexbarac Жыл бұрын
@@JoeStevens Then why not extract each filter into its own method. If any of the filters breaks, it will break inside the method and the stack trace will contain said method. The reason I asked is that I only use '...Default' if I expect to execute different pieces of logic if the returned object is null or not, but not for error checking.
@nielsterheijden1486
@nielsterheijden1486 Жыл бұрын
If you have a list type you can better use Find only use FirstOrDefault on IEnumerables.
@CodeWithStu
@CodeWithStu Жыл бұрын
#NoLinqMovement - Linq makes it fast to develop, but if you want to go fast, dont use linq :)
@sholland42
@sholland42 Жыл бұрын
I hate LINQ. #AllSQL.
@29Aios
@29Aios Жыл бұрын
Btw. If you want to check if a collection has only one element and then get it, it will be faster to call .Count() < 2 and then .FirstOrDefault() with check of value !=null, than just a call to .SingleOrDefault() even if you don't catch exceptions
@nickchapsas
@nickchapsas Жыл бұрын
That doesn’t make sense since count will enumerate the full collection before it does the check
@fabienmolinet8491
@fabienmolinet8491 Жыл бұрын
@@nickchapsas I agree that its innefficient. However the behavior is provider specific, EF will generate a count statement, and then a select with a top
@alphaanar2651
@alphaanar2651 Жыл бұрын
I see in the comment section some people still have wrong opinions even after "watching the whole video".
@ivandjokic3552
@ivandjokic3552 Жыл бұрын
What about First vs Find
@nickchapsas
@nickchapsas Жыл бұрын
Find is the same as FirstOrDefault
@jonb8869
@jonb8869 Жыл бұрын
Can you actually put this data into a real database like MySql or MSSql? I would be very surprised and frankly disappointed if "first" operated faster for querying primary key integers from a database. My expectation would be they are the same.
@nickchapsas
@nickchapsas Жыл бұрын
I don't know if EF Core is smart enough to understand that id is a primary key and limit it but any other non-constraint value will be faster
@battarro
@battarro Жыл бұрын
@@nickchapsas By convention a column named Id is assumed to be the primary key. From the docs: Code First infers that a property is a primary key if a property on a class is named “ID” (not case sensitive), or the class name followed by "ID". If the type of the primary key property is numeric or GUID it will be configured as an identity column.
@user-de2px1ed8k
@user-de2px1ed8k Жыл бұрын
TIL n/a is not aplicable and not non available.
@uskembayev
@uskembayev Жыл бұрын
Single
@thecubicnoobik9792
@thecubicnoobik9792 Жыл бұрын
or default
@battarro
@battarro Жыл бұрын
The difference at the database level is negligible. If you are doing a query on an indexed field, TOP 1 and TOP 2 uses the same execution plan, the same index, and the data will be located in the same node of the Btree. In terms of executions a Top 2 is a single Index seek/scan then a single Data file jump to get the data. A TOP 2 is the same single index scan, but now jump to two places to get the real data. If your column is not indexed.... Then index it. So it really is not a problem. This is a non existing problems for databases that are indexed.
@nickchapsas
@nickchapsas Жыл бұрын
That’s such bad advice that I’ll make a dedicated video on it. Brute forcing a solution to a problem that doesn’t need to exit doesn’t scale. There is a reason why you opt into indexing and it’s not the default behaviour and there is a reason why indexing can cause a plethora of problems in itself, let alone the space.
@battarro
@battarro Жыл бұрын
@@nickchapsas Instead of using a memory dataset, on which a First() will be better than Single(), give it a try with an indexed column on a sql/postgres database, and see if the theory holds. Also try it with an unindexed column and compare the results.
@battarro
@battarro Жыл бұрын
@@nickchapsas I just completed a benchmark test against a table with 500k records, grabbing the first, the middle, and the last. The results are the same, there is almost no difference when you are accessing an indexed column with a sargable query. First always wins by 10 microseconds. That is a insignificant amount. It doesn't justify sacrificing readability and possible data duplicates, for such a small amount. Granted, you don't always have the option of controlling your database, and if are forced to only use data in memory, then yes, first is better. Also, you don't provide the reason for not using indexes. You should always analyze your data queries and apply indexes as necessary. They are an integral of RDMS and they offer the best way for increasing performance.
@nickchapsas
@nickchapsas Жыл бұрын
@@battarro Indexing isn't free
@battarro
@battarro Жыл бұрын
@@nickchapsas You are correct, and there would be performances issues when updating/inserting if you decide to index every column on a given table. But a good rule of thumb is that if you are doing a query that is sargable on a column, such as email/username on the user table, you will benefit greatly from indexing. I ran the same benchmark as before, a table with 500k and i did a first/single, and the results were horrible compared with the index. It took GetRecordByFirst 129,662.1 us to get to the last item on the table, before with the index, it took 150.5 us. And without the index, that number increases steadly as O(N) as your table increases, while with the index it only increases as O(log n) flattening out. Im not saying Index everything, but you should index columns you are doing sargable operators.
@astralpowers
@astralpowers Жыл бұрын
First ladies > Single ladies
@kalleguld
@kalleguld Жыл бұрын
There are multiple single ladies, but there is only a single First lady.
@andytroo
@andytroo Жыл бұрын
re: Single() when you only have 1 match : famous last words "trust me bro, this is unique".. you going to bet the data integrity of your system against on every future code bug? ; but yes, push the unique constraint to the database where possible. or even better push the where clause down to the DB to retrieve only "1" row, and .Single() that
@nickchapsas
@nickchapsas Жыл бұрын
Your querying isn’t responsible for finding bugs on your inserts and updates. Coding defensively is fine but coding naively against your own code is not
@AlFasGD
@AlFasGD Жыл бұрын
I'd rather be first, because I'm now single and I'm not enjoying it
@faeyn
@faeyn Жыл бұрын
I wasn't even aware of Single. Great video! Makes perfect sense. Also, make sure to use a dictionary when possible to go from O(n) to O(1) lookups.
@franknavarrete2716
@franknavarrete2716 Жыл бұрын
Came for a small LINQ analysis, left with a new library to try (Faker)
@georgepagotelis
@georgepagotelis Жыл бұрын
…pull request. Remove faker! 😂
@mgbrown09
@mgbrown09 Жыл бұрын
The real way to solve this performance issue is to use a better data structure.
@nickchapsas
@nickchapsas Жыл бұрын
The better data structure is what allows you to use First and improve your performance
@adekunlealugbin4120
@adekunlealugbin4120 Жыл бұрын
First
@ryanzwe
@ryanzwe Жыл бұрын
OrDefault
@CRBarchager
@CRBarchager Жыл бұрын
@@ryanzwe OrDefault - or default will not compile.
@epiphaner
@epiphaner Жыл бұрын
This must be the first time I ever gave a "First" comment a thumbs up 😂
@ryanzwe
@ryanzwe Жыл бұрын
@@CRBarchager just edited it, originally didn't care but pair programming saves lives
@Sahuagin
@Sahuagin 10 ай бұрын
don't really agree with this. Single is useful as an assertion that there should logically only be 1 item in the result set and to throw otherwise. really what you're using here is a linear search/filter on a 10,000 item collection. this is true for both First and Single. First can exit early if the item it wants is at the top, but regardless if you are searching through a large enough list you should be using a database index or dictionary or some other more efficient way of finding a match. choosing between First and Single is not a performance decision; in most cases there will be a logically correct choice (usually Single/SingleOrDefault).
@antosha2224
@antosha2224 Жыл бұрын
Actually i don't see any reasonable scenario in your business logic where you should use Single(). This method doing too much things. It's just break the rule of pure functions.
@kylekeenan3485
@kylekeenan3485 Жыл бұрын
Yes, I think most already use .FirstOrDefault() but Nick is here to teach and he does a good job of that and shows it using benchmarks.
@RobinHood70
@RobinHood70 Жыл бұрын
I'm probably the outlier here, but it's because of gotchas like these that I almost never use LINQ. LINQ is great for what it is, but I"ve found that most of the time, I'm better off writing and optimizing my own code than trusting a generalized library to do so. Of course, that comes with its own tradeoffs in terms of time taken to write and optimize that code, so YMMV.
@reikooters
@reikooters Жыл бұрын
Same here in avoiding LINQ. I stay away from EF as well. One thing I've picked up from this channel is to actually benchmark and check the performance of something when I'm not sure, rather than assume something will work this or that way and should be faster or slower - especially when benchmarks are fairly quick to write using that library. Had the same feeling when I read the comments on the video suggesting not to use exceptions for the application flow - there seemed to be a lot of people in the comments using exceptions in that way.
@MaximilienNoal
@MaximilienNoal Жыл бұрын
I guess that makes your code compatible with C# 2.0. That's OLD.
@RobinHood70
@RobinHood70 Жыл бұрын
@@fusedqyou As Nick demonstrated, there's a huge performance drop if you don't use Single the right way. Another one I've seen is a couple of times is iterating through an IEnumerable repeatedly in a loop. It's not that LINQ itself is bad, but it gives a lot of opportunities for unwitting programmers to be...extremely unwitting.
@RobinHood70
@RobinHood70 Жыл бұрын
@@MaximilienNoal I'm not sure how you would jump to that conclusion. LINQ is a library, like anything else. What version you target has no bearing on whether you use the library. My code uses the latest features, just like I'm sure many other people do...it just happens that that doesn't include LINQ in the vast majority of cases.
@RobinHood70
@RobinHood70 Жыл бұрын
@@fusedqyou Just as an exercise, compare what I said to what you said. Me: "LINQ is great for what it is". You: "LINQ is a bad choice". Me: "I almost never use LINQ". You: "drop LINQ altogether". Me: "comes with its own tradeoffs...YMMV" You: "you're a bit paranoid".
@DryBones111
@DryBones111 Жыл бұрын
I usually really enjoy your videos but this could easily have been a YT short. I am slightly concerned that the performance implications are not painfully obvious to developers.
@ikerdiaz1278
@ikerdiaz1278 Жыл бұрын
I think you forget something important: if you use First you should use it after an OrderBy. Maybe if you have the data pre-ordered you can omit it, but in general you don´t know the order, and if you're using LinqToSql is mandatory to put the OrderBy. You can trust the constraints and be sure there is only one item, but this is something you know, not something "the code says". I prefer to use Single whenever I cant, I think is much more clear. If there are performance problems the refactor it. Great video and channel!
@nickchapsas
@nickchapsas Жыл бұрын
Absolutely not. Ordering by first will make you go through the whole colletion first to make sure its ordered and then get the first value. It totally misses the whole point since it will perform as slow as Single and if the person writing the code doesn't know how to proprerly handle enumerables it can also allocate the whole collection again. The whole point of the video is that on unordered data sets, first will have better performance on average.
@davearkley7014
@davearkley7014 Жыл бұрын
This is important, your benchmarks are using a presorted list which gives the result for First[OrDefault] will be the first ID which matches. I'd like to see the benchmarks repeated to find a fullname, requiring a sort of the collection as this emulates the real world case more closely..
@pinkfloydhomer
@pinkfloydhomer Жыл бұрын
@@nickchapsas I disagree. In the case where you actually get a result instead of default, you have no idea what you get without OrderBy(). Of course if you don't care about the order, that's fine. But in many cases it's an anti-pattern. It might as well be called RandomOrDefault(). Anyway, they serve different purposes, one is for getting the first if any, the other is for ensuring that there is exactly one or zero. Both have their uses and they don't replace each other. And of course, performance is not everything. Expressivity and state of intent is also important. SingleOrDefault() clearly states intend and is by it's nature agnostic about ordering, FirstOrDefault() is clearly about ordering (if you need it). Also, there is a separate discussion when we're talking Linq to EF.
@ikerdiaz1278
@ikerdiaz1278 Жыл бұрын
@@nickchapsas obviously you are right in performance comment, but in general you need the OrderBy. For example in your little example: a customer with X emails, you want to send only one email. You can use First if you don´t care about the order, but maybe the customer emails have and "PreferedOrder" field so you must use it to order the emails. In any case I think we are in the same page, the only problem is the naming: there should be an extension method called ".SingleAndITrustInMyDataDontCheck()" (but shorter) that internally calls First :)
@QwDragon
@QwDragon Жыл бұрын
@@pinkfloydhomer you don't need to sort anything when you want to get the only element. And even if you want top 1 from multiple matching, unless you are using sql, using MaxBy will be much better then sorting because max is O(n) when sort is O(n*lb(n)).
@J0nny_
@J0nny_ Жыл бұрын
kzbin.info/www/bejne/kIW6nWWpbbiWg8U Great video but I think you meant to say 'SingleOrDefault' 🤔
@B1aQQ
@B1aQQ Жыл бұрын
I don't get the point of this video. Single and First have different use cases. They are not interchangable so the performance difference shouldn't be compared. You either need to be sure there is only one result or you don't care and just want the first one.
@nickchapsas
@nickchapsas Жыл бұрын
Did you watch the full video? It answers your question
@davidmartensson273
@davidmartensson273 Жыл бұрын
The reason is that many do not understand that difference and trigger a lot of unnecessary processing where a First would be not only enough but also a lot faster.
@B1aQQ
@B1aQQ Жыл бұрын
@@nickchapsas I did, but the database constraint argument doesn't convince me. DB is sort of a dependency for DbSet in my repository and I don't trust it to have that constraint. Maybe if it's code first and it's somehow tested and ensured, but even then I should be writing "dependency agnostic" code.
@nickchapsas
@nickchapsas Жыл бұрын
@@B1aQQ It doesn't matter. If your app's business logic is to only have one of something then First is sufficient. Your reads aren't your profilers and they have no job troubleshooting your app. You should have appropriate safeguards and not making your queries exponensially slower as your data grows.
@B1aQQ
@B1aQQ Жыл бұрын
@@nickchapsas Yea, you're right. Doesn't make sense to do a sort of "runtime validation" for my data cohesion on each read.
@BeanCoffeeBean
@BeanCoffeeBean Жыл бұрын
*Looks in the comments* seems I am the only one who uses .Find() 😅
@nickchapsas
@nickchapsas Жыл бұрын
Find will work the same way as First
@abeker
@abeker Жыл бұрын
@@nickchapsas FirstOrDefault actually (and in EF if the entity is already present in the context then Find won't query the database)
Where are types allocated in .NET and why people get it so wrong
14:35
100😭🎉 #thankyou
00:28
はじめしゃちょー(hajime)
Рет қаралды 40 МЛН
100❤️
00:19
Nonomen ノノメン
Рет қаралды 38 МЛН
Do you have a friend like this? 🤣#shorts
00:12
dednahype
Рет қаралды 48 МЛН
The best way to create a string in C# that you shouldn't use
16:41
Nick Chapsas
Рет қаралды 70 М.
Don't throw exceptions in C#. Do this instead
18:13
Nick Chapsas
Рет қаралды 248 М.
Why .NET's memory cache is kinda flawed
14:13
Nick Chapsas
Рет қаралды 54 М.
What are record types in C# and how they ACTUALLY work
15:36
Nick Chapsas
Рет қаралды 116 М.
Double the Performance of your Dictionary in C#
15:12
Nick Chapsas
Рет қаралды 64 М.
You are mocking the HttpClient the wrong way
13:56
Nick Chapsas
Рет қаралды 48 М.
What is Span in C# and why you should be using it
15:15
Nick Chapsas
Рет қаралды 247 М.
Stop using the HttpClient the wrong way in .NET
10:14
Nick Chapsas
Рет қаралды 182 М.
The history of the dynamic type in C# and why I don't use it
15:49
Nick Chapsas
Рет қаралды 40 М.
100😭🎉 #thankyou
00:28
はじめしゃちょー(hajime)
Рет қаралды 40 МЛН