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:
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:
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 ...
source to share
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.
source to share
http://msdn.microsoft.com/pl-pl/library/bb738708%28v=vs.110%29.aspx - try this but I have no idea about performance
source to share