Как да заредите свързани обекти по бърз начин

Бих искал да заредя Test по id, включително всички свързани TestRuns и всички Measurements с помощта на DbContext/EntityFramework от MySql база данни.

Това е схемата на базата данни:

въведете описание на изображението тук

Какво опитах досега:

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));
    }
}

За съжаление това отнема много време, за да завърши (около една минута за 1 тест/1 тест/15 000 измервания). Опитах се да разбера генерирания SQL код с помощта на програма за профилиране на заявки, но не можах да осмисля огромния чудовищен SQL израз.

Можете ли да се сетите за по-добър (т.е. по-бърз) начин за зареждане на данните чрез DbContext?


Актуализация

Друг опит, който също води до дълго време за зареждане:

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;
}

Зареждането на измерванията отнема 84% от времето:

въведете описание на изображението тук

Това е съответният sql оператор за извличане на измерванията:

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

Копирах всеки от получените sql изрази (от трите DbContext/DbSet заявки) от профилиращия заявка в MySqlWorkbench и всеки за себе си работи много бързо. Сега съм още по-объркана...


Актуализация 2

Изолирах функцията GetTestComplete (вижте по-горе) в единична единица/тест за производителност и все още отнема много време. Резултатът от програмата за профилиране на заявки показва, че отделните sql команди са много бързи, въпреки че завършването на целия тест отнема около 5 секунди. Объркването нараства...

въведете описание на изображението тук


person nabulke    schedule 10.12.2014    source източник
comment
Ако искате само да прочетете данните (не да ги промените), можете да използвате DbSet.AsNoTracking(). Мисля, че много време се поглъща от мениджъра на състоянието на обекта и коригирането на отношенията. Ако трябва да промените данни, мисля, че трябва да опитате да извлечете само това, което трябва да промените.   -  person Gert Arnold    schedule 12.12.2014
comment
@GertArnold: Бяхте прав: DbSet.AsNoTracking() ще свърши работа и ще намали времето за заявка на измерванията от 4 s на 400 ms. Но как да използвам AsNoTracking() с тази заявка DbContext.Entry(testRun).Collection(tr => tr.Measurements).Load();?   -  person nabulke    schedule 12.12.2014
comment
@GertArnold: О, и благодаря за първия ви коментар! С удоволствие ще го приема като отговор, ако го преместите от коментар в отговор.   -  person nabulke    schedule 12.12.2014


Отговори (2)


Изпълнението на заявка е едно нещо. EF ще направи това много бързо. Съвсем друго нещо е материализирането на обекти на обекти, създаване на DbEntityEntry и обекти за връзка за инструмента за проследяване на промените.

Ако извлечете обекти от...

DbSet.AsNoTracking()

... създаването на тези DbEntityEntrys е извадено от процеса, което обикновено значително увеличава производителността.

Ако приложите AsNoTracking, можете да използвате само Include за зареждане на свързани обекти. Изказване като...

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

...ще се провали, защото няма да има запис за testRun на първо място, и методът Load е противоположен на AsNoTracking, нещо като, защото е проектиран да зарежда проследени обекти в контекст, без да ги връща.

person Gert Arnold    schedule 12.12.2014
comment
Как да направя заявка за един тест по id, включително всички тестове и всички измервания? Опитах DbSet.AsNoTracking().Where(t => t.Id == id).Include(t => t.TestRuns.Select(tr => tr.Measurements)).SingleOrDefault(), но това ще доведе до EntityCommandExecutionException. - person nabulke; 12.12.2014
comment
Съобщение за изключение Lost connection to MySQL server during query - person nabulke; 12.12.2014
comment
OMG, това вероятно е специфично за MySQL. Никога не виждам това да се случва със Sql сървър. В Sql Server това вероятно е предотвратено чрез активиране на множество активни набори от резултати, но AFAIK няма нищо подобно в MySQL. - person Gert Arnold; 12.12.2014
comment
Благодаря много за помощта Герт. - person nabulke; 12.12.2014

http://msdn.microsoft.com/pl-pl/library/bb738708%28v=vs.110%29.aspx - опитайте това, но нямам представа за производителността

person Krzysztof Skowronek    schedule 10.12.2014
comment
Това е, което вече правя в първия си пример по-горе (т.е. използвайки Include). - person nabulke; 10.12.2014