powered by simpleCommunicator - 2.0.53     © 2025 Programmizd 02
Форумы / Microsoft SQL Server [игнор отключен] [закрыт для гостей] / Почему так сильно различаются планы запроса с Option(recompile) и без? И как это побороть?
47 сообщений из 47, показаны все 2 страниц
Почему так сильно различаются планы запроса с Option(recompile) и без? И как это побороть?
    #39371270
uaggster
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Есть запрос (прошу прощения за синтаксис, это выдрано из 1C, и сгенерировано тоже автоматически 1Сом):

Код: sql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
DECLARE @P1 NUMERIC(6, 0) = 201611
	,@P2 NUMERIC(6, 0) = 201611
	,@P3 BINARY (4) = 0x0000006F
	,@P4 NUMERIC(1, 0) = 1

SELECT T1._IDRRef
FROM _Document111 T1 WITH (NOLOCK)
WHERE (
		(T1._Fld1712 >= @P1)
		AND (T1._Fld1712 <= @P2)
		)
	AND T1._IDRRef IN (
		SELECT CASE 
				WHEN T2._Fld2977_TYPE = 0x08
					AND T2._Fld2977_RTRef = @P3
					THEN T2._Fld2977_RRRef
				ELSE 0xFF
				END AS Q_001_F_000RRef
		FROM _AccumRg2973 T2 WITH (NOLOCK)
		WHERE (T2._Fld2976 = @P4)
		)


Он имеет радикально разный априорный и фактический планы , если добавить OPTION (RECOMPILE) (см. приложенную картинку):
Для сравнения, Ad hoc запрос имеет план, совпадающий с с планом после OPTION (RECOMPILE), третий план на той же картинке:
Код: sql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
SELECT T1._IDRRef
FROM _Document111 T1 WITH (NOLOCK)
WHERE (
		(T1._Fld1712 >= 201611)
		AND (T1._Fld1712 <= 201611)
		)
	AND T1._IDRRef IN (
		SELECT CASE 
				WHEN T2._Fld2977_TYPE = 0x08
					AND T2._Fld2977_RTRef = 0x0000006F
					THEN T2._Fld2977_RRRef
				ELSE 0xFF
				END AS Q_001_F_000RRef
		FROM _AccumRg2973 T2 WITH (NOLOCK)
		WHERE (T2._Fld2976 = 1)
		)


При этом запрос без OPTION (RECOMPILE) считается пару часов (и даже больше), а с опцией - менее 10 с. И адхок считается тоже 10 с.
Но это 1С, и, как вы понимаете, никаких хинтов вставить - не получится.

Почему так происходит? И как с этим бороться???
Сервер:
Microsoft SQL Server 2014 (SP2-GDR) (KB3194714) - 12.0.5203.0 (X64)
Sep 23 2016 18:13:56
Copyright (c) Microsoft Corporation
Standard Edition (64-bit) on Windows NT 6.3 <X64> (Build 9600: )

Статистика по таблицам - свежая, с полным сканированием, индексы перестроены.
Даже ребилд таблиц сделан!
...
Рейтинг: 0 / 0
Почему так сильно различаются планы запроса с Option(recompile) и без? И как это побороть?
    #39371271
uaggster
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Вот планы
...
Рейтинг: 0 / 0
Почему так сильно различаются планы запроса с Option(recompile) и без? И как это побороть?
    #39371278
Владислав Колосов
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
uaggster,

потому, что для разного значения параметров может выбираться разный план. Сервер запомнил несколько планов и не всегда попадает в оптимальный.
RECOMPILE вызывает очистку кэша планов выполнения для данного запроса. То же самое, например, может происходить после переиндексации таблиц, входящих в запрос.
Можете попробовать использовать руководство планов с параметризацией для фиксации хорошего плана. Но это не универсальная таблетка, т.к. подходит для запросов, которые сохраняют написание.
...
Рейтинг: 0 / 0
Почему так сильно различаются планы запроса с Option(recompile) и без? И как это побороть?
    #39371280
Владислав Колосов
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Иногда помогает пересчёт статистик. Если не копаться в планах, можно попробовать.
...
Рейтинг: 0 / 0
Почему так сильно различаются планы запроса с Option(recompile) и без? И как это побороть?
    #39371281
Владислав Колосов
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Пересчет статистик тоже может привести к удалению плана из кэша.
...
Рейтинг: 0 / 0
Почему так сильно различаются планы запроса с Option(recompile) и без? И как это побороть?
    #39371288
TaPaK
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
uaggster,

RECOMPILE пробрасывает значения переменных в запрос из-за этого актуальный план строится на актуальных значениях, а не скомпилированных(в кеше), Как бороться с parameter sniffing можете гуглить, вариантов не так и много :)
прибить хинт можено и вне 1С : plan guide, query store

авторОн имеет радикально разный априорный и фактический планы,
как только не переводят estimate :)
...
Рейтинг: 0 / 0
Почему так сильно различаются планы запроса с Option(recompile) и без? И как это побороть?
    #39371292
Мистер Хенки
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
чего то у вас поиска по _AccumRg2973 нет . Сканы в "плохом" плане
...
Рейтинг: 0 / 0
Почему так сильно различаются планы запроса с Option(recompile) и без? И как это побороть?
    #39371295
TaPaK
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Мистер Хенкичего то у вас поиска по _AccumRg2973 нет . Сканы в "плохом" плане
а в хорошем?
...
Рейтинг: 0 / 0
Почему так сильно различаются планы запроса с Option(recompile) и без? И как это побороть?
    #39371296
Мистер Хенки
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
CASE
WHEN T2._Fld2977_TYPE = 0x08
AND T2._Fld2977_RTRef = 0x0000006F
THEN T2._Fld2977_RRRef
ELSE 0xFF
END AS Q_001_F_000RRef
вот это сделать как хранимое вычисляемое и индекс на него и _Fld2976 может и взлетит
...
Рейтинг: 0 / 0
Почему так сильно различаются планы запроса с Option(recompile) и без? И как это побороть?
    #39371297
Мистер Хенки
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
TaPaKМистер Хенкичего то у вас поиска по _AccumRg2973 нет . Сканы в "плохом" плане
а в хорошем?
а "хороший" не очень то хорош. Жрет проц как в последний раз
...
Рейтинг: 0 / 0
Почему так сильно различаются планы запроса с Option(recompile) и без? И как это побороть?
    #39371299
TaPaK
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Мистер ХенкиCASE
WHEN T2._Fld2977_TYPE = 0x08
AND T2._Fld2977_RTRef = 0x0000006F
THEN T2._Fld2977_RRRef
ELSE 0xFF
END AS Q_001_F_000RRef
вот это сделать как хранимое вычисляемое и индекс на него и _Fld2976 может и взлетит
переменную @P3 тоже в вычисляемое поле?

автора "хороший" не очень то хорош. Жрет проц как в последний раз
парралельный план и там и там, разница больше в NL vs HASH а это не проц и тд и тп
...
Рейтинг: 0 / 0
Почему так сильно различаются планы запроса с Option(recompile) и без? И как это побороть?
    #39371301
Мистер Хенки
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
TaPaKМистер ХенкиCASE
WHEN T2._Fld2977_TYPE = 0x08
AND T2._Fld2977_RTRef = 0x0000006F
THEN T2._Fld2977_RRRef
ELSE 0xFF
END AS Q_001_F_000RRef
вот это сделать как хранимое вычисляемое и индекс на него и _Fld2976 может и взлетит
переменную @P3 тоже в вычисляемое поле?

автора "хороший" не очень то хорош. Жрет проц как в последний раз
парралельный план и там и там, разница больше в NL vs HASH а это не проц и тд и тп
индекс по вычисляемому и _Fld2976
...
Рейтинг: 0 / 0
Почему так сильно различаются планы запроса с Option(recompile) и без? И как это побороть?
    #39371304
TaPaK
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Мистер Хенки,

чукча не читатель
оригинал запроса
Код: sql
1.
2.
3.
4.
5.
6.
CASE 
	WHEN T2._Fld2977_TYPE = 0x08
	AND T2._Fld2977_RTRef = @P3
	THEN T2._Fld2977_RRRef
	ELSE 0xFF
END AS Q_001_F_000RRef
...
Рейтинг: 0 / 0
Почему так сильно различаются планы запроса с Option(recompile) и без? И как это побороть?
    #39371305
Мистер Хенки
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
TaPaKпарралельный план и там и там, разница больше в NL vs HASH а это не проц и тд и тп
соединение хэшированием требует немало проца. А там по всему и обьемы немаленькие. Но если запросов мало на сервере и никому мешать не будет, то нормально.
...
Рейтинг: 0 / 0
Почему так сильно различаются планы запроса с Option(recompile) и без? И как это побороть?
    #39371310
TaPaK
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Мистер ХенкиTaPaKпарралельный план и там и там, разница больше в NL vs HASH а это не проц и тд и тп
соединение хэшированием требует немало проца. А там по всему и обьемы немаленькие. Но если запросов мало на сервере и никому мешать не будет, то нормально.
ну раз всё в памяти уместилось, то не так и много, но как вы предлагаете менять запрос в не меняемом приложении?
...
Рейтинг: 0 / 0
Почему так сильно различаются планы запроса с Option(recompile) и без? И как это побороть?
    #39371312
Мистер Хенки
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
TaPaKМистер Хенкипропущено...

соединение хэшированием требует немало проца. А там по всему и обьемы немаленькие. Но если запросов мало на сервере и никому мешать не будет, то нормально.
ну раз всё в памяти уместилось, то не так и много, но как вы предлагаете менять запрос в не меняемом приложении?
ну по идее индекс должен подхватиться запросом, а для этого приложение менять не надо. Вот поле вычисляемое придется строить, не знаю позволяет ли такие вольности 1с. Я же предлагаю, а не настаиваю.
...
Рейтинг: 0 / 0
Почему так сильно различаются планы запроса с Option(recompile) и без? И как это побороть?
    #39371314
TaPaK
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Мистер Хенки,

вы принципиально не видите переменную в запросе????
...
Рейтинг: 0 / 0
Почему так сильно различаются планы запроса с Option(recompile) и без? И как это побороть?
    #39371315
o-o
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
o-o
Гость
Мистер ХенкиTaPaKпарралельный план и там и там, разница больше в NL vs HASH а это не проц и тд и тп
соединение хэшированием требует немало проца. А там по всему и обьемы немаленькие . Но если запросов мало на сервере и никому мешать не будет, то нормально.
...и т.к. объемы немаленькие, то в самый раз NL!!!
сверху поди строк под миллион и снизу тоже, в аккурат такое считать через NL,
там логические чтения зашкаливают.
uaggster, выньте ему статистику планов и покажите, cколько там чтений в каждом случае, пусть ужаснется
----
в первом плане server считает, что в верхней таблице по условию пара строк отберется , и в нижней тоже,
сканы оценены в 0.
в следующих двух он уже видит, что реально каждый скан будет выдавать тучу строк, потому и выбрал хэш джойн.
какое счастье, что решает все же программа, а не Мистер Хенки,
последнего надо посадить вручную соединять те две таблицы, ага, в цикле
...
Рейтинг: 0 / 0
Почему так сильно различаются планы запроса с Option(recompile) и без? И как это побороть?
    #39371321
Мистер Хенки
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
TaPaKМистер Хенки,

вы принципиально не видите переменную в запросе????
а это
Код: sql
1.
AND T2._Fld2977_RTRef = @P3 

- не заметил . Тогда конечно не получится вычисляемое поле построить. Печально конечно.
...
Рейтинг: 0 / 0
Почему так сильно различаются планы запроса с Option(recompile) и без? И как это побороть?
    #39371327
uaggster
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
o-oМистер Хенкипропущено...

соединение хэшированием требует немало проца. А там по всему и обьемы немаленькие . Но если запросов мало на сервере и никому мешать не будет, то нормально.
...и т.к. объемы немаленькие, то в самый раз NL!!!
сверху поди строк под миллион и снизу тоже, в аккурат такое считать через NL,
там логические чтения зашкаливают.
uaggster, выньте ему статистику планов и покажите, cколько там чтений в каждом случае, пусть ужаснется
----
в первом плане server считает, что в верхней таблице по условию пара строк отберется , и в нижней тоже,
сканы оценены в 0.
в следующих двух он уже видит, что реально каждый скан будет выдавать тучу строк, потому и выбрал хэш джойн.
какое счастье, что решает все же программа, а не Мистер Хенки,
последнего надо посадить вручную соединять те две таблицы, ага, в цикле
В эстимейтед они считает, что скан Document111 обойдется в 600 000 строк, а Accum - 4,5 миллиона.
В актуальном - 10 000 Х 8,5 миллионов
...
Рейтинг: 0 / 0
Почему так сильно различаются планы запроса с Option(recompile) и без? И как это побороть?
    #39371366
uaggster
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Тут основная проблема в том, что это не человек писал. Это генератор 1C накодил.
И перестроить запрос - не получится.
Кстати, если построить подсказываемый индекс - то это никак делу не помогает.

Причем я сомневаюсь, что это параметер сниффинг. Потому что после DBCC FREEPROCCACHE - ничего не меняется.
Статистика актуальная, я первым делом пересчитал ее через Exec sp_MSForEachtable 'update statistics ? with fullscan'

Нет никакого трейс-флага, который заставлял бы сервер принудительно рекомпилить все запросы?
Понятно, что это не очень хорошо, но как временное решение, бока идет препирательство с разработчиками - сгодилось бы!
...
Рейтинг: 0 / 0
Почему так сильно различаются планы запроса с Option(recompile) и без? И как это побороть?
    #39371376
invm
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
uaggsterНет никакого трейс-флага, который заставлял бы сервер принудительно рекомпилить все запросы?Нету.
Plan guide вам поможет.
...
Рейтинг: 0 / 0
Почему так сильно различаются планы запроса с Option(recompile) и без? И как это побороть?
    #39371585
Basma4
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
если база в уровне соместимости 120, попробуй включить старую оценку кардинальности с помощью TF 9481 и протестировать запрос с ним.
...
Рейтинг: 0 / 0
Почему так сильно различаются планы запроса с Option(recompile) и без? И как это побороть?
    #39371643
uaggster
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Basma4, да, в 120
Но трейсфлаг не помог. Оценка кардинальности осталась прежней.
Причем оптимизатор по-прежнему ошибается.
...
Рейтинг: 0 / 0
Почему так сильно различаются планы запроса с Option(recompile) и без? И как это побороть?
    #39371646
TaPaK
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
uaggsterBasma4, да, в 120
Оценка кардинальности осталась прежней.

это какой? 5+?

авторПричем оптимизатор по-прежнему ошибается. все любят оскорблять оптимизатор, а он для вас старается и выбирает самый дешёвый по ресурсам план
...
Рейтинг: 0 / 0
Почему так сильно различаются планы запроса с Option(recompile) и без? И как это побороть?
    #39371654
TaPaK
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
кстати, включите, если не включён Trace Flag 4199
...
Рейтинг: 0 / 0
Почему так сильно различаются планы запроса с Option(recompile) и без? И как это побороть?
    #39371673
Владислав Колосов
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
uaggster,

авторПотому что после DBCC FREEPROCCACHE - ничего не меняется.
С чего бы изменилось, если это процедурный кэш, а не кэш запросов.
...
Рейтинг: 0 / 0
Почему так сильно различаются планы запроса с Option(recompile) и без? И как это побороть?
    #39371691
uaggster
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Владислав Колосовuaggster,

авторПотому что после DBCC FREEPROCCACHE - ничего не меняется.
С чего бы изменилось, если это процедурный кэш, а не кэш запросов.
Эээ... еще раз, по пунктам... Есть какой то отдельный кэш запросов?
И параметризованный запрос с точки зрения энжин - это не хранимая процедура?
...
Рейтинг: 0 / 0
Почему так сильно различаются планы запроса с Option(recompile) и без? И как это побороть?
    #39371701
TaPaK
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
uaggsterВладислав Колосовuaggster,

пропущено...

С чего бы изменилось, если это процедурный кэш, а не кэш запросов.
Эээ... еще раз, по пунктам... Есть какой то отдельный кэш запросов?
И параметризованный запрос с точки зрения энжин - это не хранимая процедура?
с точки зрения "энжин" (за что его так) ad hoc, а не хранимая процедура. Но всё равно они в PROCCACHE...
...
Рейтинг: 0 / 0
Почему так сильно различаются планы запроса с Option(recompile) и без? И как это побороть?
    #39371814
Фотография SomewhereSomehow
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
uaggster,

Добрый день.
Выбор того или иного типа соединения в плане запроса обусловлен двумя главными причинами:
1) стоимость
2) принципиальная "выполнимость" логической операции соединения физическим оператором соединения

В вашем случае, играет роль второй пункт.

Попробуйте дописать в ваш запрос, вместо option(recompile) - option(hash join), вы получите ошибку:
"Query processor could not produce a query plan because of the hints defined in this query. Resubmit the query without specifying any hints and without using SET FORCEPLAN."

Чтобы понять почему, нужно посмотреть на конструкцию
Код: sql
1.
2.
3.
4.
5.
6.
7.
		T1._IDRRef IN (
		SELECT 
			CASE 
				WHEN T2._Fld2977_TYPE = 0x08 AND T2._Fld2977_RTRef = @P3
				THEN T2._Fld2977_RRRef
				ELSE 0xFF
			END AS Q_001_F_000RRef


Когда вы пишите "столбец1 in (столбец2 из подзапроса)" это означает логическую операцию полусоединения (Semi Join) по условию столбец1 = столбец2.

В вашем же запросе, в зависимости от @P3 это условие может быть либо "столбец1 = столбец2", либо "столбец1 = константа".
Соединение хэшированием (Hash Join) или слиянием (Merge Join, кроме full) - требует хотя бы одного предиката равенства в соединении (equijoin), т.е. операцию "столбец1 = константа" (можно представить себе это как некую вариацию "cross join"), выполняет только оператор Nested Loops. Который раз за разом, по числу строк из верхней таблицы, сканирует нижнюю, а точнее заполняет Spool и читает оттуда. Это очень долго.

Если же вы пишете option(recompile), то оптимизатор подставляет вместо параметров константы, так как если бы они были написаны литералами в запросе (это называется Parameter Embedding Optimization), тогда проблема с переменным условие соединения уходит и оптимизатор сразу переключается более выгодный алгоритм соединения, т.е. данном случае Hash Join.

Что тут в итоге можно сказать, причина не в стоимости и не в плохих оценках, а в том, что "универсальные запросы работают универсально плохо". Единственный вменяемый вариант, пока 1С-ники переписывают запрос, это, как уже тут советовали - руководство планов (plan guide), которое бы применяло к этому запросу хинт "recompile". В хелпе такой вариант даже указан в качестве наиболее типичных примеров использования plan guides :
Attach Query Hints to a Plan Guide Common Query Hints Used in Plan Guides
Queries that can benefit from plan guides are generally parameter-based, and may be performing poorly because they use cached query plans whose parameter values do not represent a worst-case or most representative scenario. The OPTIMIZE FOR and RECOMPILE query hints can be used to address this problem. OPTIMIZE FOR instructs SQL Server to use a particular value for a parameter when the query is optimized. RECOMPILE instructs the server to discard a query plan after execution, forcing the query optimizer to recompile a new query plan the next time that the same query is executed . For an example, see Plan Guides.
...
Рейтинг: 0 / 0
Почему так сильно различаются планы запроса с Option(recompile) и без? И как это побороть?
    #39371904
o-o
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
o-o
Гость
SomewhereSomehowПопробуйте дописать в ваш запрос, вместо option(recompile) - option(hash join), вы получите ошибку
...
Если же вы пишете option(recompile), то оптимизатор подставляет вместо параметров константы,
...
тогда проблема с переменным условие соединения уходит

...а я еще думаю, озверел он что ли, при оценках
автор они считает, что скан Document111 обойдется в 600 000 строк , а Accum - 4,5 миллиона
выбрать NL, это воистину надо быть Мистером Хенки.
т.е. меня это смутило, но нисколько не заставило задуматься о том, что hash join может быть невозможен,
ведь он есть на соседнем плане.
спасибо!!!
...
Рейтинг: 0 / 0
Почему так сильно различаются планы запроса с Option(recompile) и без? И как это побороть?
    #39371957
Фотография SomewhereSomehow
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
SomewhereSomehowпроблема с переменным условие соединения уходит
Перечитал, решил уточнить на всякий случай.
Это не то, что у нас во время выполнения Has Join в столбце _Fld2977_RTRef не может быть значения <> 0x0000006F и выполнение не может пойти по ветке "столбец1 = константа", а то что условие перестает быть переменным и альтернатива "столбец1 = константа" / "столбец1 = столбец2" превращается в "столбец1 = столбец2", где в роли "столбца2" выступает выражение, известное в момент (ре)компиляции и сервер может построить экви соединение, что он и делает:


И не может получить такое же условие, когда имеется параметр и переменное условие соединения:
...
Рейтинг: 0 / 0
Почему так сильно различаются планы запроса с Option(recompile) и без? И как это побороть?
    #39372131
SomewhereSomehow,

А почему нельзя вычислять кейс и хешджойнить по результату?
...
Рейтинг: 0 / 0
Почему так сильно различаются планы запроса с Option(recompile) и без? И как это побороть?
    #39372137
TaPaK
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Любопытный гостьSomewhereSomehow,

А почему нельзя вычислять кейс и хешджойнить по результату?
а вот если вы посмотрите на его план с recompile, то узнаете что когда значения известны так и есть
...
Рейтинг: 0 / 0
Почему так сильно различаются планы запроса с Option(recompile) и без? И как это побороть?
    #39372182
Фотография SomewhereSomehow
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Любопытный гость,

Я объяснил выше почему, потому что оптимизатор не знает какое будет значение параметра во время выполнения и должен гарантировать "универсальный план" под все возможные значения, а предикат соединения может меняться из-за параметра, а hash-у обязательно нужен один equi join, вот простой пример:
Код: sql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
use tempdb;
go
if object_id ('t1') is not null drop table t1;
if object_id ('t2') is not null drop table t2;
create table t1(a int not null, b int not null, c int check (c between 1 and 50), constraint pk_a primary key(a));
create table t2(b int not null, c int, d char(10), constraint pk_b primary key(b));
insert into t1(a,b,c) select number, number%100+1, number%50+1 from master..spt_values where type = 'p' and number between 1 and 1000;
insert into t2(b,c) select number, number%100+1 from master..spt_values where type = 'p' and number between 1 and 1000;
go

-- 1) OK - hash join with hint
declare @p int = 1;
select 
	*
from 
	t1
where
	t1.a in (select case when t2.c = @p then t2.b else 1 end from t2)
option(recompile, hash join);
go

-- 2) Error: Query processor could not produce a query plan because of the hints defined in this query. Resubmit the query without specifying any hints and without using SET FORCEPLAN.
-- No join condidition, similar to "cross join", not supported by hash
declare @p int = null;
select 
	*
from 
	t1
where
	t1.a in (select case when t2.c = @p then t2.b else 1 end from t2)
option(recompile, hash join);
go

-- 3) Ok - no hints, same @p = null value - Loops join
declare @p int = null;
select 
	*
from 
	t1
where
	t1.a in (select case when t2.c = @p then t2.b else 1 end from t2)
option(recompile);
go


Во всех случаях я добавил рекомпиляцию.

В первом случае, я ограничил выбор только хэш соединением и в качестве значения параметра задал 1.
При рекомпиляции условие было преобразовано в "case when t2.c = 1 then t2.b else 1 end".

Во втором случае, параметр null, при рекомпиляции условие было преобразовано в "case when t2.c = null then t2.b else 1 end", часть t2.c = null очевидно никогда не может быть true, по этому эта ветка была выкинута на этапе упрощения, осталось только проверить равенство на единицу, а условие соединения теперь фактически исчезло - нет предиката равенства, по этому хэш джойн невозможен и мы получаем ошибку.

В третьем случае, параметр тоже нулл, но я убрал ограничение на хэш и в плане вы увидите соединение вложенными циклами. Попробуйте найти в плане, в Nested Loops условие по которому соединяются таблицы (свойства Outer Refernce или Predicate), вы увидите что их нет, идет просто соединение таблиц вложенными циклами, предикат соединения был упрощен.

Конечно, у ТС там два предиката и формально оптимизатор мог бы что-то сделать, но тут наверное уже работает "консерватизм" оптимизатора, там где потенциально возможно получить некорректные результаты оптимизатор без нужды не упрощает.

Обычно такие манипуляции с условиями в соединения говорят о не очень удачно схеме данных, но я не 1С-ник, так что на этом умолкаю =)
...
Рейтинг: 0 / 0
Почему так сильно различаются планы запроса с Option(recompile) и без? И как это побороть?
    #39372287
SomewhereSomehowЯ объяснил выше почему, потому что оптимизатор не знает какое будет значение параметра во время выполнения и должен гарантировать "универсальный план" под все возможные значенияСпасибо.
Возможно я не понимаю элементарщину...
Если взглянуть на план первого запроса из Вашего примера там будет Compute Scalar по формуле [Expr1008] = Scalar Operator(CASE WHEN [tempdb].[dbo].[t2].[c]=(1) THEN [tempdb].[dbo].[t2].[b] ELSE (1) END) и по результату будет Hash build.
Почему нельзя в формуле сразу написать [Expr1008] = Scalar Operator(CASE WHEN [tempdb].[dbo].[t2].[c]=(@p) THEN [tempdb].[dbo].[t2].[b] ELSE (1) END) ? Почему тогда план станет не универсальным?

Возможно спросил глупость...
...
Рейтинг: 0 / 0
Почему так сильно различаются планы запроса с Option(recompile) и без? И как это побороть?
    #39372325
Фотография SomewhereSomehow
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Любопытный гость,

Нет, вопрос не глупый, как я писал выше, потому, что сервер не может построить корректное условие по эквисоединению (для Build или Probe), а вы видимо спрашиваете почему именно не может.
Пусть вам ответит сам разработчик оптимизатора Крейг Фридман, лучше чем у меня не получится =)
https://blogs.msdn.microsoft.com/craigfr/2009/04/28/implied-predicates-and-query-hints/

По данной проблеме далее в комментариях:
hackace April 6, 2012 at 8:11 pmHi craige,

can you help me ?
there are two TSQL sentences :sentence 1 and sentence 2
The sentence 1 can be excuted successfully ,but there will be throw an exception when I excuted the sentence 2,why?
Код: sql
1.
2.
3.
4.
5.
6.
7.
8.
9.
--sentence 1
use [AdventureWorks]
go
DECLARE @c VARCHAR(10)
SET @c = ''
SELECT CustomerID
FROM dbo.Customers AS C
WHERE CustomerID IN (SELECT  @c + CustomerID FROM dbo.Orders)
OPTION (HASH JOIN, RECOMPILE)



--sentence 2
Код: sql
1.
2.
3.
4.
5.
6.
7.
8.
use [AdventureWorks]
go
DECLARE @c VARCHAR(10)
SET @c = ''
SELECT CustomerID
FROM dbo.Customers AS C
WHERE CustomerID IN (SELECT  @c + CustomerID FROM dbo.Orders)
OPTION (HASH JOIN)


Craig Freedman April 10, 2012 at 9:53 amHi,

The first query succeeds because as noted in the above post, with the recompile hint, the optimizer substitutes the empty string constant for the variable @c. You can see the substitution by checking the compute scalar in the plan:

Код: sql
1.
2.
3.
4.
 |–Hash Match(Left Semi Join, HASH:([C].[CustomerID])=([Expr1006]), RESIDUAL:([Northwind].[dbo].[Customers].[CustomerID] as [C].[CustomerID]=[Expr1006]))
      |–Index Scan(OBJECT:([Northwind].[dbo].[Customers].[Region] AS [C]))
      |–Compute Scalar(DEFINE:([Expr1006]=N''+[Northwind].[dbo].[Orders].[CustomerID]))
           |–Index Scan(OBJECT:([Northwind].[dbo].[Orders].[CustomersOrders]))



Without the recomile hint, the optimizer cannot do the substitution. I believe it then incorrectly concludes that @c is not a runtime constant and further concludes that it cannot safely use the hash join since it would need to reevaluate the orders subquery for each row from the customers table. I'm afraid that I'm not aware of any workaround other than to remove hash join hint.

Craig

Это я и имел ввиду, когда писал выше:
SomewhereSomehow Конечно, у ТС там два предиката и формально оптимизатор мог бы что-то сделать, но тут наверное уже работает "консерватизм" оптимизатора, там где потенциально возможно получить некорректные результаты оптимизатор без нужды не упрощает.
Проще говоря - не может и все. Заведите item на microsoft connect, скажите что требуете доработать алгоритм и почему, вам ответят с большими подробностями почему это так или наоборот, что доработают (в чем я сомневаюсь).
...
Рейтинг: 0 / 0
Почему так сильно различаются планы запроса с Option(recompile) и без? И как это побороть?
    #39372326
Фотография SomewhereSomehow
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
SomewhereSomehow,
опечатка: "лучше чем у него у меня не получится"
...
Рейтинг: 0 / 0
Почему так сильно различаются планы запроса с Option(recompile) и без? И как это побороть?
    #39372386
SomewhereSomehow,

Спасибо. Теперь понятно.
...
Рейтинг: 0 / 0
Почему так сильно различаются планы запроса с Option(recompile) и без? И как это побороть?
    #39372627
Владислав Колосов
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
SomewhereSomehow,

Следует ли из вышесказанного, что выгоднее использовать объединение с табличной переменной или временной таблице вместо использования констант, если есть сомнения?
...
Рейтинг: 0 / 0
Почему так сильно различаются планы запроса с Option(recompile) и без? И как это побороть?
    #39372629
Владислав Колосов
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Переменных, конечно же, а не констант. Если оптимизатор полагает, что там может быть что-то еще, а не скаляр (что странно, на мой взгляд, пусть даже и NULL).
...
Рейтинг: 0 / 0
Почему так сильно различаются планы запроса с Option(recompile) и без? И как это побороть?
    #39373855
uaggster
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
SomewhereSomehow, большое спасибо!
Абсолютно исчерпывающе и понятно.
Самое обидное, я даже вроде читал об этом, и слушал лекцию (АФАИК Зайцева Дмитрия, если не путаю). А увидев в жизни - утупился.

Еще раз спасибо!
...
Рейтинг: 0 / 0
Период между сообщениями больше года.
Почему так сильно различаются планы запроса с Option(recompile) и без? И как это побороть?
    #39859974
AlxOlm
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
uaggster,

Эээ!?
А что спасибо? Как проблема то решилась?
...
Рейтинг: 0 / 0
Почему так сильно различаются планы запроса с Option(recompile) и без? И как это побороть?
    #39862268
Фотография МуМу
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Ну для 1С-а и подобных систем мы например сделали продукт который может добавлять опции типа (recompile) и т.п.
А что касается вашего случая то вы должны обратить внимание при Hash join на оперативную память которую потребляет запрос. Сталкивался с ситуацией когда подобных запросов было очень много в единицу времени и сервер принимал решение переходить в долгие вложенные циклы. А была ситуация совокупностью факторов, одним из которых было объединение по ключу с индексированной строкой (255) в которой максимальные значения были до 10-и символов. По сути решением проблемы стало сокращение размерности поля.
...
Рейтинг: 0 / 0
Почему так сильно различаются планы запроса с Option(recompile) и без? И как это побороть?
    #39862273
Фотография Критик
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
AlxOlm,

можно просто план закрепить
...
Рейтинг: 0 / 0
Почему так сильно различаются планы запроса с Option(recompile) и без? И как это побороть?
    #39862307
uaggster
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
AlxOlm, никак не решилось.
Взял распечатку топика, пошел к лидеру разработчиков и сказал - "идете на... юг" (прошу прощения за географические подробности).
Я не разработчик, я dba, мне - простительно.
...
Рейтинг: 0 / 0
Почему так сильно различаются планы запроса с Option(recompile) и без? И как это побороть?
    #39974131
vi0
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
uaggster
AlxOlm, никак не решилось.
Взял распечатку топика, пошел к лидеру разработчиков и сказал - "идете на... юг" (прошу прощения за географические подробности).
Я не разработчик, я dba, мне - простительно.
все еще не решилось?
...
Рейтинг: 0 / 0
47 сообщений из 47, показаны все 2 страниц
Форумы / Microsoft SQL Server [игнор отключен] [закрыт для гостей] / Почему так сильно различаются планы запроса с Option(recompile) и без? И как это побороть?
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]