Как улучшить код Linq-To-Sql

Использование класса StackExchange.Profiling.MiniProfiler для профилирования приложения ASP.NET MVC с Linq-To-Sql в качестве ORM.

Я пытаюсь сократить одно действие до одного SQL, чтобы у меня больше не было дубликатов. Поэтому я соответствующим образом изменил свой код linq-to-sql, но это не оказало положительного влияния на скорость.

Затем я проверил время, необходимое для SQL.

Это показывает MiniProfiler:

введите здесь описание изображения

Когда я запускаю точно такой же SQL в Management Studio, он работает очень быстро:

введите здесь описание изображения

Вот код:

from t in type
let tDoc = (from d in context.documents
            where d.Key == t.No
            && d.RType == (int)RType.Art
            && d.AType == (int)AType.Doc
            select d).FirstOrDefault(d => d.UseForThumb)
select new Time
{
    Id = t.Id,
    //... more simple mappings here
    // then a complex one:
    DocsCount = context.documents.Count(d =>
        (d.Key == t.Id.ToString()
        && d.RType == (int)RType.Type
        && d.AType == (int)AType.Doc)
        ||
        (d.Key == t.No
        && d.RType == (int)RType.Art
        && d.AType == (int)AType.Doc)),

    // and another one
    ThumbId = (tDoc != null && tDoc.FRKey.HasValue) ? tDoc.FRKey.Value : 0
};

В чем может быть причина такой огромной разницы? - Изменить: нет никакой разницы, я просто неправильно истолковал SSMS :(

В любом случае, моя проблема сохраняется. Что я могу изменить, чтобы сделать его быстрее?

Я когда-то читал, что отображение из Linq-To-Sql имеет проблему с производительностью. Есть ли способ обойти это?


person Philipp M    schedule 25.04.2013    source источник
comment
У вас одинаковая производительность: 1 с в вашем коде и в SSMS, не так ли?   -  person remi bourgarel    schedule 25.04.2013
comment
О, это так? Я хоть в SSMS это 1 мс! Обидно! Все еще медленно извлекать эти 12 строк...   -  person Philipp M    schedule 25.04.2013
comment
используйте fdottrace для выяснения того, что происходит, хватит гадать!   -  person remi bourgarel    schedule 25.04.2013
comment
Я начал трассировку на SqlServer с помощью Sql Server Profiler и получил много информации, но я еще не знаю, что с ней делать... поэтому я учусь прямо сейчас. Я тоже попробую fdotrace.   -  person Philipp M    schedule 25.04.2013
comment
ваша проблема не с сервером sql, используйте dotrace, чтобы выяснить, какая часть вашего кода медленная: шаблон, sql, вычисления...   -  person remi bourgarel    schedule 25.04.2013
comment
Что ж, запрос SQL является узким местом, когда я проверяю MiniProfiler...   -  person Philipp M    schedule 25.04.2013
comment
Загрузите профиль, сгенерированный в SQL Server Profiler, в помощник по настройке базы данных (SSMS -> Инструменты — помощник по настройке базы данных) и посмотрите, какие рекомендации были сделаны.   -  person Halceyon    schedule 25.04.2013
comment
выполнить ваш запрос в SSMS и отобразить фактический план выполнения, здесь вы сможете узнать, что требует больше всего ресурсов/времени для выполнения.   -  person remi bourgarel    schedule 26.04.2013
comment
Сейчас я пробую советник по настройке базы данных.   -  person Philipp M    schedule 26.04.2013
comment
Я добавил несколько индексов, но это не улучшило скорость запроса.   -  person Philipp M    schedule 26.04.2013
comment
В плане выполнения я вижу, что операция Filter стоит 82%, что, как я предполагаю, связано с тем, что она фильтрует 17 788 096 строк...   -  person Philipp M    schedule 26.04.2013
comment
Теперь я пытаюсь выяснить, почему фильтруется так много строк, потому что в реальных таблицах всего 30 000 и 50 000 строк.   -  person Philipp M    schedule 26.04.2013


Ответы (1)


Я сделал несколько проб и ошибок и изменил код Linq-To-Sql на это:

from t in types
let docs = context.documents.Where(d => (d.RKey == t.Id.ToString()
                                     && d.RType == (int)RType.Type
                                     && d.AType == (int)AType.Doc)
                                   ||
                                        (d.RKey == t.No 
                                     && d.RType == (int)RType.Art 
                                     && d.AType == (int)AType.Doc))
let tDoc = docs.FirstOrDefault(d => d.RType == (int)RType.Art && d.UseForThumb)
let docsCount = docs.Count()
select new Time
{                                               
  Id = t.Id,
  //... more simple mappings here
  DocsCount = docsCount,
  ThumbId = (tDoc != null && tDoc.FRKey.HasValue) ? tDoc.FRKey.Value : 0,
}

Это значительно ускорило запрос.

person Philipp M    schedule 29.04.2013