One Trick To Improve EF Core Performance Using Query Splitting

Sdílet
Vložit
  • čas přidán 18. 06. 2024
  • ☄️ Master the Modular Monolith Architecture: bit.ly/3SXlzSt
    📌 Accelerate your Clean Architecture skills: bit.ly/3PupkOJ
    🚀 Support me on Patreon to access the source code: / milanjovanovic
    In this video, I'll show you how to improve EF Core Performance using Query Splitting. Query splitting is an EF Core feature introduced back in .NET 5. I'll show you how to use Query splitting to improve performance, and how to configure EF Core to use Query splitting at the DbContext level. Also, I will talk about the pros and cons of using Query splitting with EF Core.
    One Trick To Improve Entity Framework Performance
    www.milanjovanovic.tech/blog/...
    Join my weekly .NET newsletter:
    www.milanjovanovic.tech
    Subscribe for more:
    czcams.com/users/MilanJovano...
    Chapters
    0:00 What is Query Splitting?
    0:25 Setting the scene
    2:08 Single SQL query
    3:54 Query Splitting in action
    7:03 Behavior with missing records
    7:58 Configuring Query Splitting on DbContext
  • Věda a technologie

Komentáře • 105

  • @MilanJovanovicTech
    @MilanJovanovicTech  Před rokem +44

    A few people pointed out that the second version is "slower", which you can see around the 4:30 mark.
    That was a request hitting a cold start, unfortunately.
    I tested it now and:
    - Single query: ~8ms
    - Split query: ~5ms
    I admit that I may have made an error here, leading you to believe it is in fact slower with query splitting.
    As I said in the video, measure everything and never take anyone's (including mine) word as the "truth".
    I'll try to do a better job with this in future videos!
    Stay awesome 😁

    • @vladyslavhrehul2185
      @vladyslavhrehul2185 Před rokem +2

      Thanks for the video.
      Just wanted to mention 1 thing which is hard for me to hear :) :
      why are pronouncing "SEQUEL" instead of "SQL"?
      You can check wiki, where it is explained why "SEQUEL" is not correct to name it now and for long period of time too.

    • @MilanJovanovicTech
      @MilanJovanovicTech  Před rokem +1

      ​@@vladyslavhrehul2185 You are the very first one to bring that up 😅

    • @krccmsitp2884
      @krccmsitp2884 Před rokem +1

      @@vladyslavhrehul2185 It's a long lasting tradition at Microsoft to pronounce acronyms word-like.

  • @zeeshanasghar3751
    @zeeshanasghar3751 Před rokem +1

    very informative, will implement in my project. thanks for sharing another wonderful video

  • @shuvo9131
    @shuvo9131 Před rokem +1

    Thank you and awesome explanation.

    • @MilanJovanovicTech
      @MilanJovanovicTech  Před rokem

      Glad you liked it! Do you think you can use this in your project somewhere?

  • @onursedef9091
    @onursedef9091 Před rokem +1

    From 21 seconds to 5 seconds. I am pretty impressed by this feature. Thank you for showing.

  • @filippoquaranta3419
    @filippoquaranta3419 Před rokem +1

    Thanks for this video explanation

  • @erosnemesis
    @erosnemesis Před rokem +2

    This feature greatly improved my performance 10x! Maybe not that much but it was immediately noticed

    • @MilanJovanovicTech
      @MilanJovanovicTech  Před rokem

      Wow, that's an amazing improvement! You must've had a lot of JOINs in that query

  • @sergiom.954
    @sergiom.954 Před rokem +1

    Wow I am discovering your channel and I have found extremely useful things

    • @MilanJovanovicTech
      @MilanJovanovicTech  Před rokem

      Thanks Sergio, hopefully the algorithm will get me in front of more and more people 😁

  • @fernandocalmet
    @fernandocalmet Před rokem +1

    Very interesting, this lesson improves a lot in query performance. Thank you very much for sharing Milan👏😁

    • @MilanJovanovicTech
      @MilanJovanovicTech  Před rokem +1

      Thank you Fernando. Do you have an idea where you could apply this?

    • @fernandocalmet
      @fernandocalmet Před rokem

      @@MilanJovanovicTech Of course, I would apply it to all my queries where I do joins with other entities. I find it great to be able to add it by behavior and for simple queries define them right there with the "AsSingleQuery()" method. Correct me if I'm wrong please :D

  • @MrJonjoe1977
    @MrJonjoe1977 Před rokem +1

    First time I've come across this. Looks like it could be useful for some larger ef queries. Much appreciated

    • @MilanJovanovicTech
      @MilanJovanovicTech  Před rokem

      I wrote a blog post also with some examples:
      www.milanjovanovic.tech/blog/how-to-improve-performance-with-ef-core-query-splitting

    • @bloopers2967
      @bloopers2967 Před 7 měsíci

      ​@@MilanJovanovicTechpage not exists

    • @MilanJovanovicTech
      @MilanJovanovicTech  Před 7 měsíci

      @@bloopers2967 Fixed it!

  • @escobar4599
    @escobar4599 Před rokem +3

    Never noticed this capability before, so appreciate it being called out. I often just split queries by hand and join in memory. As you say - often a complex query is slower than multiple smaller ones. I will certainly look at this splitting capability though, it might save me some effort.
    Not strictly NET related, but since you mentioned the potential cost to multiple queries depending on proximity of data, I would mention the most impressive complex query performance remedy I have been using quite a lot recently, is using FOR JSON. In a corporate environment with MS SQL cluster spanning datacenters, consumed by APIs also spanning datacenters - we aren't always ensured of a short trip from client to the current primary node. By structuring the data as JSON from the SQL we reduce the replicated column data and the resulting payload is a fraction of the original rowset. Since JSON is a bit chatty itself, we actually use a SQL scalar function - to generate the raw JSON result (text) and then compress the result (byte array). Its simple in code to decompress what SQL has compressed with stock NET Gzip (IIRC) implementation, and deserialize to the resulting object type. You end up with a structured result like what you would do in EF projection, but tightly compressed to flow back across the wire to the client - at the cost of CPU rather than IO. I have yet to dig in to how SQL does it, but in all tests to date a FOR JSON query with many subqueries performs best (for us, YMMV) when compared to a single query with numerous joins to related data expressed as a rowset.

    • @MilanJovanovicTech
      @MilanJovanovicTech  Před rokem +1

      That sounds super interesting! I'm going to have to explore this topic deeper

    • @bloopers2967
      @bloopers2967 Před rokem +1

      Can you guys please give any documentation where i can read about this method in detail, thanks in advance

    • @MilanJovanovicTech
      @MilanJovanovicTech  Před rokem

      @@bloopers2967 learn.microsoft.com/en-us/sql/relational-databases/json/format-query-results-as-json-with-for-json-sql-server?view=sql-server-ver16

  • @ramesha4969
    @ramesha4969 Před rokem +1

    Nice 👏

  • @BatShvit
    @BatShvit Před rokem +1

    great feature!

    • @MilanJovanovicTech
      @MilanJovanovicTech  Před rokem

      Did you try it out?

    • @BatShvit
      @BatShvit Před rokem

      @@MilanJovanovicTech Yes, of course. This is good for speeding up requests, especially under load.

  • @mahmudx
    @mahmudx Před rokem +1

    I usually do load nested objects when it is required one by one. After just getting an object by Id, I do some checking, if it passes, then I load the nested object when it is required. It saves some time, I think. I never benchmarked though.

  • @alexmadnix
    @alexmadnix Před rokem +1

    Ace Milan Jovanović

  • @RajK09
    @RajK09 Před rokem +1

    Nice tutorial, you got a new subscriber 👍
    How did you enable logging SQL queries in console? I need this

    • @MilanJovanovicTech
      @MilanJovanovicTech  Před rokem

      I set the log level to Information in appsettings.json
      A video on Logging is actually coming out in an hour 😁

  • @jaomartins1994
    @jaomartins1994 Před rokem +4

    Entity could just use the gathering id to fetch attendees and invitations from database, instead of doing a join with inner query 😅, nice video by the way, keep up the good work! 🚀

    • @MilanJovanovicTech
      @MilanJovanovicTech  Před rokem +1

      It is interesting how it translates the SQL indeed!

    • @morganishere123
      @morganishere123 Před rokem +1

      I think this might be deliberate, as joins are more performant then saying "WHERE GatheringId = {0}" on the Attendees table. I haven't tried this myself but I'm betting that if projection is used, the split queries won't Select every column on the Gathering table either.

  • @jawadahmed7336
    @jawadahmed7336 Před rokem +1

    please make a detail video on layered architecture using identity and ef core

  • @atifsaeedkhan9207
    @atifsaeedkhan9207 Před rokem +1

    Hi, Just one question, I can see multiple includes are being used, what if I want a parameter of list for all these 3 includes and include them dynamically? How to achieve it?

    • @MilanJovanovicTech
      @MilanJovanovicTech  Před rokem

      Construct the query dynamically by iterating that list to determine what to inlcude

    • @atifsaeedkhan9207
      @atifsaeedkhan9207 Před rokem

      @@MilanJovanovicTech would u mind send me the code for the same please.

  • @henkvandergeld5104
    @henkvandergeld5104 Před rokem +1

    What did you do to get the sql in the console/output of the IDE?

  • @KarwanEssmat
    @KarwanEssmat Před rokem +1

    Well done,
    I created separate queries for both ( single and AsSplitQuery). I just invoke inneeded one.

  • @ibrahimal-zaidi6436
    @ibrahimal-zaidi6436 Před rokem +1

    Hi Milan,
    I have a question, currently I'm working on a big API project to build API for a database with 114 tables.
    So:
    1. who can I generates Dtos for all Entities?
    2. Do I need to build controllers for all tables? all Entities ? or just the Important one?
    3. Any design guide or ideas I will appreciate that.
    Thx.

    • @MilanJovanovicTech
      @MilanJovanovicTech  Před rokem

      1. Write code? Or scaffold from the database
      2. I don't know. Depends on your application
      3. Use a layered architecture

  • @udayughareja
    @udayughareja Před rokem +1

    place matters?. if i place as split at the bottom (before materializing) does it change anything?

  • @sarabia630
    @sarabia630 Před rokem +2

    Hi! I'm again here to make the "scalability" question. Using EF as it manages his own connection pool different than ADO. What should we do to configure max connection pool and queueing to prevent EF from crashing? A collegue found an issue where I try to access to an endpoint simulating 1000 concurrent users simultaneously with a simple query done with ADO and EF. ADO gets to 100% pool but it always returns an answer but EF gets to 100% and FAILS to return, it looks like it manages wrong the queue, any help here?
    By the way, if you select all columns in EF it will also go way slower than selecting the ones you use and use way more memory (for 1 to many relations with big results this does a very big difference).

    • @MilanJovanovicTech
      @MilanJovanovicTech  Před rokem

      "but EF gets to 100% and FAILS to return" - what is the error you are getting in that case?

    • @sarabia630
      @sarabia630 Před rokem

      @@MilanJovanovicTech System.AggregateException: One or more errors occurred. (Timeout expired. The timeout period elapsed prior to obtaining a connection from the pool. This may have occurred because all pooled connections were in use and max pool size was reached.)----- This error does not happen with ADO/Dapper. Test was for about 1000 virtual users making requests all the time during 1 minute.

  • @tasin5541
    @tasin5541 Před 9 měsíci +1

    How do you test the split query vs single query performance properly locally? What if the actual app service and db servers are close but the local environment is on another server with more latency?

    • @MilanJovanovicTech
      @MilanJovanovicTech  Před 9 měsíci

      Then test it with the remote database?

    • @tasin5541
      @tasin5541 Před 9 měsíci

      @@MilanJovanovicTech the latency to remote db is high from local environment because each is in a different region. But the api is hosted in the same region as db, so the actual latency is low.
      So split query could perform badly on the local environment with round trips to remote db but it could actually perform better on the server.

    • @aakashpoojary3968
      @aakashpoojary3968 Před 5 měsíci

      ​@@tasin5541I have the same issue dealing with writing queries from local and testing it with remote db, the response time isn't that great but if we test it from a server where the latency is low the response time is significantly better.

  • @muhammadsaifullah411
    @muhammadsaifullah411 Před rokem +1

    How can we generate sql query in command line window.?

  • @EzequielRegaldo
    @EzequielRegaldo Před 11 měsíci +1

    Im having troubles scaling net ef core, i cant do more than 200 rps. With Nestjs with same data structure, db and etc .. im doing 5000 qps, can you show us how to tune it for heavy loads ? Im using postgresql

    • @MilanJovanovicTech
      @MilanJovanovicTech  Před 11 měsíci +1

      What queries are you running? How big is your database?

    • @EzequielRegaldo
      @EzequielRegaldo Před 11 měsíci

      @@MilanJovanovicTech they are 5 strings with uuid without joins or complexity with a limit of 25 characters

  • @cyrildouglas9262
    @cyrildouglas9262 Před rokem +1

    How about if we use Implicit Join instead of include? does AsSplitQuery has any benefit in that case? I assume when we use Implicit Join "AsNoTracking" isn't required as well, am I right?

    • @MilanJovanovicTech
      @MilanJovanovicTech  Před rokem

      AsNoTracking is if we don't want to track changes with EF.
      In this case, it's not required.
      You mean using the LINQ Join method?
      It won't make much difference I expect, since it's translated to the same SQL statement more or less.

    • @cyrildouglas9262
      @cyrildouglas9262 Před rokem +1

      I mean .Select() method which we use DTO(s) to transfer the only required fields instead all the entity using .Include() method, I'm not sure if AsSplitQuery has any effect in that case.

    • @MilanJovanovicTech
      @MilanJovanovicTech  Před rokem +1

      @@cyrildouglas9262 I'm not sure, going to check.

    • @dmitrywho7990
      @dmitrywho7990 Před rokem

      @Cyril Douglas .Select does nothing to the problem cartesian explosion poses. it is just an additional (and i recommend it as well) way to reduce db traffic
      AsSplitQuery has effect in both cases because after .Select you still have remaining parent child relationships which in a flattened response increase the amount of data

    • @cyrildouglas9262
      @cyrildouglas9262 Před rokem

      @@dmitrywho7990 Thanks for the reply, however there are some drawbacks using SpliQuery as Microsoft stated that there is no guarantee for data consistency using this method, as well as it implies more roundtrips to the database, even them consider to use this carefully.

  • @ramytawfik9168
    @ramytawfik9168 Před rokem +1

    another question please:
    Can you please tell me the difference between both queries ?
    var result1 = dbContext.Authors.Include(x => x.Books);
    var result2 = from author in dbContext.Authors
    from book in dbContext.Books.Where(x => x.AuthorId == author.Id)
    select new { author, book };

    • @MilanJovanovicTech
      @MilanJovanovicTech  Před rokem

      One is LINQ, the other is 'query syntax'. And I think they get compiled to the same SQL, so no difference in theory.

    • @ramytawfik9168
      @ramytawfik9168 Před rokem

      @@MilanJovanovicTech do the one with query syntax is lazy loaded ?

    • @MilanJovanovicTech
      @MilanJovanovicTech  Před rokem

      @@ramytawfik9168 They're both eager loading

    • @ramytawfik9168
      @ramytawfik9168 Před rokem

      @@MilanJovanovicTech thanks a lot bro

  • @MilanJovanovicTech
    @MilanJovanovicTech  Před rokem +1

    Every Saturday morning, I send one .NET tip in my newsletter.
    *2625 .NET engineers* already read it. I would love to have you with us.
    www.milanjovanovic.tech/

  • @phugia963
    @phugia963 Před rokem +1

    First time u sent it, postman recorded 30ms, then split query & it became 638ms, how is this an improvement? Just curious.

    • @MilanJovanovicTech
      @MilanJovanovicTech  Před rokem +1

      That was a request hitting a cold-start, actually.
      I tested it now and:
      - Single query: ~8ms
      - Split query: ~5ms
      I admit that I may have made an error here, leading you to believe it is in fact slower with query splitting.
      But you should measure everything.
      Listen from this part:
      czcams.com/video/GY7QwSFeVBQ/video.html

    • @phugia963
      @phugia963 Před rokem +1

      @@MilanJovanovicTech thanks for the update 👍

    • @MilanJovanovicTech
      @MilanJovanovicTech  Před rokem

      @@phugia963 ​ I added a pinned comment also, so that everyone is aware. Thanks for pointing that out. 😁

  • @gasparinizuzzurro6306
    @gasparinizuzzurro6306 Před rokem +1

    not so sure about this improvement. sending multiple queries to the engine involves the latency needed to process each one.
    there is not only the latency introduced by network (that is some situations means not a local server but a TCP connection over the network), but also the time needed to go into the steps of parse-optimize-reduce-generate plan query cycle. For relatively small queries this time is comparable to the time to effectively execute the query itself.
    Plus with multiple queries you tend to prevent some optimizations the SQL Query engine could perform when the query was specified only once.

    • @MilanJovanovicTech
      @MilanJovanovicTech  Před rokem +1

      Agreed, and I mentioned this could be a potential deal breaker for using this feature.
      That's why although Query Splitting may seem like a good idea on the surface, you have to be careful with it and measure the performance changes.

  • @scorpions3834
    @scorpions3834 Před rokem +1

    time goes from 30ms to 652ms as soon as you add the split query

    • @MilanJovanovicTech
      @MilanJovanovicTech  Před rokem

      I said you have to measure if it makes sense for your use case. Not that it will *always* improve performance 😁

    • @scorpions3834
      @scorpions3834 Před rokem +1

      @@MilanJovanovicTech 😂

  • @wokoalex4658
    @wokoalex4658 Před 11 měsíci +1

    Please measure the speed for us?

  • @justanaveragebalkan
    @justanaveragebalkan Před 2 měsíci

    Or we can, actually write sql and not worry about performance :) ?

    • @MilanJovanovicTech
      @MilanJovanovicTech  Před 2 měsíci

      Sure, I was never against writing SQL. SQL is more important than any ORM.

  • @noctavel
    @noctavel Před rokem +1

    Very informative video, but what a horrible hack to bypass SQL faults

    • @MilanJovanovicTech
      @MilanJovanovicTech  Před rokem

      What would you propose?

    • @noctavel
      @noctavel Před rokem

      @@MilanJovanovicTech idk. Just came here to criticize withouth any further workaround 🤣🤣. But i trully believe sql engines should deal with it more elegantly

  • @guava_dev
    @guava_dev Před rokem +1

    Over the past year I've started moving away from EF. I love the code first concept and how easy EF is to use. However, that ease of use is (from what I'm seeing) making a lot of devs lazy and they end up not understanding what the tool is doing when it builds the queries.

    • @MilanJovanovicTech
      @MilanJovanovicTech  Před rokem

      With a bit of effort, you can make it work easily. Even for complex queries. You mentioned that you're moving away from EF - into what?

    • @guava_dev
      @guava_dev Před rokem +1

      @@MilanJovanovicTech I should clarify a little better. I've started moving away from EF Core on the query side to Dapper. I still use EF Core for migrations and writes. When building my queries I start in SSMS to make sure I'm squeezing all the performance I can in raw SQL. Problem with using EF Core is that it's not always so simple to translate that query over. I've been using Net Core since the RC days and don't get me wrong, EF Core has come far, but I think it took too long for basic functionality to make it's way from EF to EF Core

    • @MilanJovanovicTech
      @MilanJovanovicTech  Před rokem

      @@guava_dev I agree, I also prefer Dapper these days.

  • @complicated2359
    @complicated2359 Před rokem +1

    To be a program efficient, it should not use any framework like ef. Only something li dapper is on a brick of efficiency.

  • @chswin
    @chswin Před rokem +1

    😂 query splitting…

  • @techpc5453
    @techpc5453 Před rokem +1