Почему этот hql намного быстрее, чем при использовании критериев? - PullRequest
0 голосов
/ 03 августа 2011

Я использую nhibernate как ORM.И один из моих выборов невероятно медленный.Дело в том, что генерация sql занимает много времени.Я уверен, что это не сам SQL-запрос, который медленный, потому что я рассчитал сам запрос с помощью SQL-профилировщика.И это показало, что между началом выполнения кода nhibernate и запросом, отправляемым в базу данных, есть промежуток ~ 15 секунд.Сам сгенерированный SQL-запрос выполняется так же быстро, как и ожидалось.

Код выбора (в репозитории) выглядит следующим образом

public IEnumerable<Document> GetAllDocumentsReadyForDeletion()
{
    return from doc in _session.Query<Document>()
           where doc.StorageType == 'D'
           select doc;
}

Я также пытался:

return _session.CreateCriteria<Document>()
        .Add(Restrictions.Eq("StorageType", 'D'))
        .List<Document>();

что эквивалентно (верно?).Тем не менее, они оба работают примерно одинаково (медленно, примерно 15 секунд для генерации SQL-запроса)

Это, однако, работает так быстро, как я хочу, и я понятия не имею, почему:

return _session.CreateQuery(
        "from Document doc where doc.StorageType = 'D'")
        .List<Document>();

Я действительно хочу использовать версию linq to nhibernate.Есть идеи, почему код работает по-другому?(Если вам нужно больше деталей, просто спросите!)

Edit1

О, боже, я сделал глупую ошибку или что-то другое? Я ошибочно прочитал неправильный столбец вsql profiler .. ЭМ, фактическое время выполнения для первых двух ~ 18 секунд, для третьего ~ 0 сек.Я пытаюсь найти различия в sql atm ...

Edit2

Это на самом деле становится совершенно другим вопросом.Получающиеся запросы почти точно такие же, за исключением того, что первые два заключены в "exec sp_executesql"

Теперь я немного проследил это с помощью анализатора запросов, и медленный запрос имеет один шаг:

clustered index scan.

Быстрый запрос состоит из двух шагов:

Index seek
Bookmark lookup

Есть ли у вас что-нибудь подобное?

Ответы [ 2 ]

1 голос
/ 04 августа 2011

Они на самом деле генерируют разные sql. Один из которых использует индекс, а другой - нет. Вот почему. Почему один из них использует индекс, а другой нет, это содержание для следующего вопроса.

(упрощенно) Сгенерированный SQL

Быстрая версия:

SELECT Id, Name FROM documents WHERE StorageType = 'D'

Медленная версия (как linq, так и критерии) (ввод из памяти atm, проверю позже):

sp_execsql N'SELECT Id, Name FROM documents WHERE StorageType = @p0', N'@p0 nchar(1)', N'D'

обратите внимание, что тип StorageType относится к типу varchar (1). Это сообщение в блоге объясняет, почему это медленно

Проблема здесь в том, что @ p0 передается как NCHAR (1) (он же символ Unicode), который не соответствует индексу столбца с не-Unicode. Это случаи индекса сканирования.

По-видимому, сканирование таблицы занимает около 17 секунд для этой таблицы.

0 голосов
/ 03 августа 2011

Это разные пути в NHibernate для получения одних и тех же данных.Они строят запросы, используя другой код.Есть обсуждения по поводу проблемы с linq-провайдером NHibernate.Я закончил тем, что написал свой собственный поставщик LINQ для предоставления мне LINQ в NHibernate, который просто создает строку во втором примере, а затем использует ее для получения данных.

...