How to quickly load related objects

I would like to load Test

by id including all related TestRuns

and everything Measurements

using DbContext / EntityFramework from MySql database.

This is the database schema:

enter image description here

What I have tried so far:

public class TestRepository : Repository<Test>, ITestRepository
{
    public IQueryable<Test> GetTestComplete(int id)
    {
      return DbSet.Where(t => t.Id == id)
                  .Include(t => t.TestRuns.Select(tr => tr.Measurements));
    }
}

      

Unfortunately, it takes a very long time (about one minute for 1 test / 1 Testrun / 15000 Measurements). I tried to understand the generated SQL using Query Profiler but couldn't understand the huge monster SQL statement.

Can you think of a better (i.e. faster) way to load data using DbContext?


Update

Another try, also resulting in looong load times:

public Test GetTestComplete(int id)
{
    Test test = DbSet.Find(id);
    DbContext.Entry(test).Collection(t => t.TestRuns).Load();
    foreach (var testRun in test.TestRuns)
    {
        // next line takes a lot of time!
        DbContext.Entry(testRun).Collection(tr=>tr.Measurements).Load(); 
    }
    return test;
}

      

Loading measurements takes 84% โ€‹โ€‹of the time:

enter image description here

This is the appropriate sql statement for extracting dimensions:

SELECT 
Extent1.id,
Extent1.test_run_id,
Extent1.rss_dbm
FROM measurement AS Extent1
WHERE Extent1.test_run_id = :EntityKeyValue1

      

I copied each of the resulting SQL queries (from the 3 queries DbContext

/ DbSet

) from the Query Profiler in MySqlWorkbench and each one is very fast. Now I am even more confused ...


Update 2

I've isolated the function GetTestComplete

(see above) in a unit / performance test and it still takes a long time. The output from the query profiler shows that the individual sql commands are very fast, although the whole test takes about 5 seconds. Confusion grows ...

enter image description here

+3


source to share


2 answers


Making a request is one thing. EF will do it very quickly. Quite different is materializing entity objects, creating DbEntityEntry

relationship objects for the change tracker.

If you retrieve objects using ...

DbSet.AsNoTracking()

      

... the creation of these DbEntityEntry

is taken out of the process, which usually improves performance significantly.



If you apply AsNoTracking

, you can Include

only use to load related objects. A statement like ...

DbContext.Entry(testRun).Collection(tr => tr.Measurements).Load();

      

... will fail because in the first place there will be no entry for testRun

, and the method Load

is the opposite AsNoTracking

, sort of because it is meant to load tracked objects into the context without returning them.

+2


source


http://msdn.microsoft.com/pl-pl/library/bb738708%28v=vs.110%29.aspx - try this but I have no idea about performance



-1


source







All Articles