Магическая проблема производительности

Мне часто приходится решать проблемы с производительностью и последние два дня борюсь с запросом, который мне просто вынес мозг. 

Запрос большой и строится динамически, поэтому я запустил сайт, подключился к нему дебагером и выцепил из кода SQL запрос. Запускаю его в SQL Server Management Studio, и он выполняется за 4 секунды максимум. Но когда абсолютно этот же код выполняется в коде сайта, он работает более минуты.

Я потратил целый день на то, что менял запрос в разные стороны, добавлял OPTION (RECOMPILE) на случай, если проблема с планом выполнения, танцевал вокруг компьютера и ничего не помогало. 

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

Потом я решил запустил профайлер и выцепить запрос оттуда, и его там показали следующим образом:

exec sp_executesql N'

SELECT ...

...

...

...

 

OFFSET @OffSet ROWS

FETCH NEXT @PageSize ROWS ONLY  OPTION(RECOMPILE)',

  N'@OffSet int,

  @PageSize int,

  @appServerTimeStamp 

  @CurrentSessionUserId int',

  @OffSet=0,@PageSize=50,

  @appServerTimeStamp='2018-05-04 07:14:08.193',

  @CurrentSessionUserId=53792'

И когда я выполняю этот запрос в SQL Server Management Studio запрос явно умирает на минуту. Опа, что за прикол. Убираю sp_executesql, выполняю запрос без этого и он выполняется мгновенно. Что за хрень, думаю я.

Начались новые танцы, какого черта sp_executesql убивает производительность. Я начал убирать части запроса и в определенный момент запрос начал выглядеть вот так:

exec sp_executesql N'

SELECT ...

...

...

...

 

OFFSET @OffSet ROWS

FETCH NEXT @PageSize ROWS ONLY  OPTION(RECOMPILE)

',

  N'@OffSet int,

  @PageSize int,

  @appServerTimeStamp 

  @CurrentSessionUserId int',

  @OffSet=0,@PageSize=50,

  @appServerTimeStamp='2018-05-04 07:14:08.193',

И он выполнился мгновенно. Столько мата вырвалось из моего рта. Как? Если ты не заметил разницы, то в конце запроса появился символ новой строки. После ONLY  OPTION(RECOMPILE) появился переход на новую строку и это сделало запрос великолепным. 

Бывает такое, что изменение запроса изменяет план выполнения и запрос выполняется по-другому. Но я не уверен, что эта теория здесь пройдет. Я менял запрос, убирая ONLY  OPTION(RECOMPILE), я пробовал добавить в конце пробел, вместо перехода на новую строку, но запрос оставался медленным. И только символ новой строки в самом конце заставляет запрос выполнятся не минуту, а секунду. 

Сегодня весь день сижу и тестирую этот случай, пытаюсь понять причину такого поведения. Можно просто добавить символ новой строки в конце, но не люблю магию. 

Продолжение здесь.


Понравилось? Кликни Лайк, чтобы я знал, какой контент более интересен читателям. Заметку пока еще никто не лайкал и ты можешь быть первым


Комментарии

Леонид

04 Мая 2018

Нихрена себе, ну ты мегамозг! Жду продолжения


MasDen

04 Мая 2018

Первый раз про такие чудеса читаю а сам и подавно не сталкивался. Если разберетесь будет интересно узнать причины.


Илья

05 Мая 2018

Баг или фича?


Михаил Фленов

05 Мая 2018

Единственное нормальное объяснение - это все же глюк с планом выполнения. В понедельник продолжу играл и если проблему нельзя больше воспроизвести, это точно глюк с кэшем. Хотя  я его сбрасывал.


Добавить Комментарий

Еще что-нибудь

Хотите найти еще что-то интересное почитать? Можно попробовать отфильтровать заметки на блоге по категориям.

О блоге

Программист, автор нескольких книг серии глазами хакера и просто блогер. Интересуюсь безопасностью, хотя хакером себя не считаю

Обратная связь

Без проблем вступаю в неразборчивые разговоры по e-mail. Стараюсь отвечать на письма всех читателей вне зависимости от страны проживания, вероисповедания, на русском или английском языке.

Пишите мне