NHibernate Linq Query в 3 раза медленнее, чем HQL

У меня есть простой тест, который запускает запрос 5000 раз. Версия linq запроса занимает в 3 раза больше HQL, а кэшированная версия Linq значительно медленнее, чем кешированная версия HQL

HQL:

session.CreateQuery(String.Format("from Episode where SeriesId='{0}' and SeasonNumber='{1}' and EpisodeNumber='{2}'", seriesId, seasonNumber, episodeNumber))
               .SetMaxResults(1)
               .SetCacheable(true)
               .UniqueResult<Episode>();

Linq:

session.Query<Episode>()
       .Where(c => c.SeriesId == seriesId && c.SeasonNumber == seasonNumber && c.EpisodeNumber == episodeNumber)
       .Cacheable()
       .FirstOrDefault();

Вот результаты

HQL:   Cached: less than a second   No-Cache: 5 seconds
LINQ:  Cached: 8 seconds            No-Cache: 15 seconds

Я просто хочу убедиться, что я испытываю ожидаемые накладные расходы, а не то, что я делаю неправильно.

Если это над головой есть, и я не могу много сделать, можете ли вы предложить, возможно, среднюю площадку, которая потребует меньше строк, но обеспечит лучшую производительность?

Примечание: Настройка кеша в Fluent Nhibernate .Cache(c => c.UseQueryCache().UseSecondLevelCache().UseMinimalPuts().ProviderClass<HashtableCacheProvider>())

Ответы

Ответ 1

Я думаю, проблема в следующем. Этот запрос:

session.Query<Episode>()
       .Where(c => c.SeriesId == seriesId && c.SeasonNumber == seasonNumber && c.EpisodeNumber == episodeNumber)
       .Cacheable()
       .FirstOrDefault();

загружает все эпизоды из базы данных, помещает их в кеш, а затем возвращает первый экземпляр коллекции. Когда вызывается FirstOrDefault, выполняется запрос для Where(c => c.SeriesId == seriesId && c.SeasonNumber == seasonNumber && c.EpisodeNumber == episodeNumber), а затем применяется FirstOrDefault для всей возвращенной последовательности.

Что-то вроде:

  • .Where(c => c.SeriesId == seriesId && c.SeasonN... Выполняется SQL
  • .FirstOrDefault() оценивается по всем элементам набора 1.

Итак, если вы попробуете что-то вроде

session.Query<Episode>()
       .Where(c => c.SeriesId == seriesId && c.SeasonNumber == seasonNumber && c.EpisodeNumber == episodeNumber)
       .Cacheable()
       .SetMaxResults(1)
       .UniqueResult();

он должен вести себя так же, как ваш HQL-запрос.