В този отговор се фокусирам върху първоначалното наблюдение:заявката, генерирана от EF, е бавна, но когато същата заявка се изпълнява в SSMS, тя е бърза.
Едно възможно обяснение на това поведение е Снифиране на параметри .
И така, EF генерира заявка, която има малко параметри. Първият път, когато стартирате тази заявка, сървърът създава план за изпълнение за тази заявка, като използва стойности на параметри, които са били в сила при първото изпълнение. Този план обикновено е доста добър. Но по-късно изпълнявате същата EF заявка, като използвате други стойности за параметри. Възможно е за нови стойности на параметрите предварително генерираният план да не е оптимален и заявката да става бавна. Сървърът продължава да използва предишния план, защото все още е същата заявка, само стойностите на параметрите са различни.
Ако в този момент вземете текста на заявката и се опитате да я стартирате директно в SSMS, сървърът ще създаде нов план за изпълнение, защото технически това не е същата заявка, която се издава от EF приложението. Дори една разлика в знака е достатъчна, всяка промяна в настройките на сесията също е достатъчна, за да може сървърът да третира заявката като нова. В резултат сървърът има два плана за привидно една и съща заявка в своя кеш. Първият "бавен" план е бавен за новите стойности на параметрите, тъй като първоначално е бил изграден за различни стойности на параметри. Вторият "бърз" план е изграден за текущите стойности на параметрите, така че е бърз.
Статията Бавно в приложението, бързо в SSMS от Erland Sommarskog обяснява тази и други свързани области с много повече подробности.
Има няколко начина да отхвърлите кешираните планове и да принудите сървъра да ги регенерира. Промяната на таблицата или промяната на индексите на таблицата трябва да го направи - трябва да отхвърли всички планове, които са свързани с тази таблица, както "бавни", така и "бързи". След това изпълнявате заявката в приложението EF с нови стойности на параметрите и получавате нов "бърз" план. Изпълнявате заявката в SSMS и получавате втори "бърз" план с нови стойности на параметрите. Сървърът все още генерира два плана, но и двата сега са бързи.
Друг вариант е добавянето на OPTION(RECOMPILE)
към заявката. С тази опция сървърът няма да съхранява генерирания план в своя кеш. Така че, всеки път, когато заявката се изпълнява, сървърът ще използва действителните стойности на параметрите, за да генерира план, който (той смята) ще бъде оптимален за дадените стойности на параметри. Недостатъкът е допълнителните разходи при генерирането на план.
Имайте предвид, че сървърът все още може да избере „лош“ план с тази опция поради остаряла статистика, например. Но поне надушването на параметри не би било проблем.
Тези, които се чудят как да добавят OPTION (RECOMPILE)
намек към заявката, която се генерира от EF, вижте този отговор:
https://stackoverflow.com/a/26762756/4116017