Мне часто приходится решать проблемы с производительностью и последние два дня борюсь с запросом, который мне просто вынес мозг.
Запрос большой и строится динамически, поэтому я запустил сайт, подключился к нему дебагером и выцепил из кода 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), я пробовал добавить в конце пробел, вместо перехода на новую строку, но запрос оставался медленным. И только символ новой строки в самом конце заставляет запрос выполнятся не минуту, а секунду.
Сегодня весь день сижу и тестирую этот случай, пытаюсь понять причину такого поведения. Можно просто добавить символ новой строки в конце, но не люблю магию.
Продолжение здесь.
Понравилось? Кликни Лайк, чтобы я знал, какой контент более интересен читателям. Заметку пока еще никто не лайкал и ты можешь быть первым
Нихрена себе, ну ты мегамозг! Жду продолжения
Первый раз про такие чудеса читаю а сам и подавно не сталкивался. Если разберетесь будет интересно узнать причины.
Баг или фича?
Единственное нормальное объяснение - это все же глюк с планом выполнения. В понедельник продолжу играл и если проблему нельзя больше воспроизвести, это точно глюк с кэшем. Хотя я его сбрасывал.
Хотите найти еще что-то интересное почитать? Можно попробовать отфильтровать заметки на блоге по категориям.