简体   繁体   中英

How to load related entities in a fast way

I'd like to load a Test by id including all related TestRuns and all Measurements using DbContext / EntityFramework from a MySql database.

This is the database schema:

在此输入图像描述

What I 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 this takes a very long time to complete (about one minute for 1 Test/1 Testrun/15000 Measurements). I tried to understand the generated SQL code by using a query profiler, but couldn't make sense of the huge monster SQL statement.

Can you think of a better (ie faster) way to load the data using DbContext?


Update

Another try, also resulting in a looong loading time:

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 the measurements takes 84% of the time:

在此输入图像描述

This is the corresponding sql statement for fetching the measurements:

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 statements (from the three DbContext / DbSet queries) from the query profiler into MySqlWorkbench , and each for itself is running very fast. Now I am even more confused...


Update 2

I isolated the function GetTestComplete (see above) in a single unit/performance test and it still takes a long time. The output of the query profiler shows that the individual sql commands are very fast, even though the whole test takes about 5 seconds to complete. Confusion growing...

在此输入图像描述

Executing a query is one thing. EF will do that very fast. Quite another thing is materializing entity objects, creating DbEntityEntry and relationship objects for the change tracker.

If you fetch entities by...

DbSet.AsNoTracking()

...creating these DbEntityEntry s is taken out of the process, which usually considerably increases performance.

If you apply AsNoTracking , you can only use Include to load related entities. A statement like...

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

...will fail, because there won't be an entry for testRun in the first place, and the Load method is the opposite of AsNoTracking , sort of, because it is designed to load tracked entities into a context without returning them.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM