|
Почему так сильно различаются планы запроса с Option(recompile) и без? И как это побороть?
|
|||
---|---|---|---|
#18+
кстати, включите, если не включён Trace Flag 4199 ... |
|||
:
Нравится:
Не нравится:
|
|||
21.12.2016, 10:40 |
|
Почему так сильно различаются планы запроса с Option(recompile) и без? И как это побороть?
|
|||
---|---|---|---|
#18+
uaggster, авторПотому что после DBCC FREEPROCCACHE - ничего не меняется. С чего бы изменилось, если это процедурный кэш, а не кэш запросов. ... |
|||
:
Нравится:
Не нравится:
|
|||
21.12.2016, 11:00 |
|
Почему так сильно различаются планы запроса с Option(recompile) и без? И как это побороть?
|
|||
---|---|---|---|
#18+
Владислав Колосовuaggster, авторПотому что после DBCC FREEPROCCACHE - ничего не меняется. С чего бы изменилось, если это процедурный кэш, а не кэш запросов. Эээ... еще раз, по пунктам... Есть какой то отдельный кэш запросов? И параметризованный запрос с точки зрения энжин - это не хранимая процедура? ... |
|||
:
Нравится:
Не нравится:
|
|||
21.12.2016, 11:17 |
|
Почему так сильно различаются планы запроса с Option(recompile) и без? И как это побороть?
|
|||
---|---|---|---|
#18+
uaggsterВладислав Колосовuaggster, пропущено... С чего бы изменилось, если это процедурный кэш, а не кэш запросов. Эээ... еще раз, по пунктам... Есть какой то отдельный кэш запросов? И параметризованный запрос с точки зрения энжин - это не хранимая процедура? с точки зрения "энжин" (за что его так) ad hoc, а не хранимая процедура. Но всё равно они в PROCCACHE... ... |
|||
:
Нравится:
Не нравится:
|
|||
21.12.2016, 11:27 |
|
Почему так сильно различаются планы запроса с Option(recompile) и без? И как это побороть?
|
|||
---|---|---|---|
#18+
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.
Когда вы пишите "столбец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. ... |
|||
:
Нравится:
Не нравится:
|
|||
21.12.2016, 12:45 |
|
Почему так сильно различаются планы запроса с Option(recompile) и без? И как это побороть?
|
|||
---|---|---|---|
#18+
SomewhereSomehowПопробуйте дописать в ваш запрос, вместо option(recompile) - option(hash join), вы получите ошибку ... Если же вы пишете option(recompile), то оптимизатор подставляет вместо параметров константы, ... тогда проблема с переменным условие соединения уходит ...а я еще думаю, озверел он что ли, при оценках автор они считает, что скан Document111 обойдется в 600 000 строк , а Accum - 4,5 миллиона выбрать NL, это воистину надо быть Мистером Хенки. т.е. меня это смутило, но нисколько не заставило задуматься о том, что hash join может быть невозможен, ведь он есть на соседнем плане. спасибо!!! ... |
|||
:
Нравится:
Не нравится:
|
|||
21.12.2016, 13:39 |
|
Почему так сильно различаются планы запроса с Option(recompile) и без? И как это побороть?
|
|||
---|---|---|---|
#18+
SomewhereSomehowпроблема с переменным условие соединения уходит Перечитал, решил уточнить на всякий случай. Это не то, что у нас во время выполнения Has Join в столбце _Fld2977_RTRef не может быть значения <> 0x0000006F и выполнение не может пойти по ветке "столбец1 = константа", а то что условие перестает быть переменным и альтернатива "столбец1 = константа" / "столбец1 = столбец2" превращается в "столбец1 = столбец2", где в роли "столбца2" выступает выражение, известное в момент (ре)компиляции и сервер может построить экви соединение, что он и делает: И не может получить такое же условие, когда имеется параметр и переменное условие соединения: ... |
|||
:
Нравится:
Не нравится:
|
|||
21.12.2016, 14:19 |
|
Почему так сильно различаются планы запроса с Option(recompile) и без? И как это побороть?
|
|||
---|---|---|---|
#18+
SomewhereSomehow, А почему нельзя вычислять кейс и хешджойнить по результату? ... |
|||
:
Нравится:
Не нравится:
|
|||
21.12.2016, 16:46 |
|
Почему так сильно различаются планы запроса с Option(recompile) и без? И как это побороть?
|
|||
---|---|---|---|
#18+
Любопытный гостьSomewhereSomehow, А почему нельзя вычислять кейс и хешджойнить по результату? а вот если вы посмотрите на его план с recompile, то узнаете что когда значения известны так и есть ... |
|||
:
Нравится:
Не нравится:
|
|||
21.12.2016, 16:50 |
|
Почему так сильно различаются планы запроса с Option(recompile) и без? И как это побороть?
|
|||
---|---|---|---|
#18+
Любопытный гость, Я объяснил выше почему, потому что оптимизатор не знает какое будет значение параметра во время выполнения и должен гарантировать "универсальный план" под все возможные значения, а предикат соединения может меняться из-за параметра, а 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.
Во всех случаях я добавил рекомпиляцию. В первом случае, я ограничил выбор только хэш соединением и в качестве значения параметра задал 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С-ник, так что на этом умолкаю =) ... |
|||
:
Нравится:
Не нравится:
|
|||
21.12.2016, 17:29 |
|
Почему так сильно различаются планы запроса с Option(recompile) и без? И как это побороть?
|
|||
---|---|---|---|
#18+
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) ? Почему тогда план станет не универсальным? Возможно спросил глупость... ... |
|||
:
Нравится:
Не нравится:
|
|||
21.12.2016, 18:49 |
|
Почему так сильно различаются планы запроса с Option(recompile) и без? И как это побороть?
|
|||
---|---|---|---|
#18+
Любопытный гость, Нет, вопрос не глупый, как я писал выше, потому, что сервер не может построить корректное условие по эквисоединению (для 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 2 Код: sql 1. 2. 3. 4. 5. 6. 7. 8.
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.
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, скажите что требуете доработать алгоритм и почему, вам ответят с большими подробностями почему это так или наоборот, что доработают (в чем я сомневаюсь). ... |
|||
:
Нравится:
Не нравится:
|
|||
21.12.2016, 19:32 |
|
Почему так сильно различаются планы запроса с Option(recompile) и без? И как это побороть?
|
|||
---|---|---|---|
#18+
SomewhereSomehow, опечатка: "лучше чем у него у меня не получится" ... |
|||
:
Нравится:
Не нравится:
|
|||
21.12.2016, 19:33 |
|
Почему так сильно различаются планы запроса с Option(recompile) и без? И как это побороть?
|
|||
---|---|---|---|
#18+
SomewhereSomehow, Спасибо. Теперь понятно. ... |
|||
:
Нравится:
Не нравится:
|
|||
21.12.2016, 21:33 |
|
Почему так сильно различаются планы запроса с Option(recompile) и без? И как это побороть?
|
|||
---|---|---|---|
#18+
SomewhereSomehow, Следует ли из вышесказанного, что выгоднее использовать объединение с табличной переменной или временной таблице вместо использования констант, если есть сомнения? ... |
|||
:
Нравится:
Не нравится:
|
|||
22.12.2016, 10:53 |
|
Почему так сильно различаются планы запроса с Option(recompile) и без? И как это побороть?
|
|||
---|---|---|---|
#18+
Переменных, конечно же, а не констант. Если оптимизатор полагает, что там может быть что-то еще, а не скаляр (что странно, на мой взгляд, пусть даже и NULL). ... |
|||
:
Нравится:
Не нравится:
|
|||
22.12.2016, 10:55 |
|
Почему так сильно различаются планы запроса с Option(recompile) и без? И как это побороть?
|
|||
---|---|---|---|
#18+
SomewhereSomehow, большое спасибо! Абсолютно исчерпывающе и понятно. Самое обидное, я даже вроде читал об этом, и слушал лекцию (АФАИК Зайцева Дмитрия, если не путаю). А увидев в жизни - утупился. Еще раз спасибо! ... |
|||
:
Нравится:
Не нравится:
|
|||
23.12.2016, 15:34 |
|
Почему так сильно различаются планы запроса с Option(recompile) и без? И как это побороть?
|
|||
---|---|---|---|
#18+
uaggster, Эээ!? А что спасибо? Как проблема то решилась? ... |
|||
:
Нравится:
Не нравится:
|
|||
10.09.2019, 17:23 |
|
Почему так сильно различаются планы запроса с Option(recompile) и без? И как это побороть?
|
|||
---|---|---|---|
#18+
Ну для 1С-а и подобных систем мы например сделали продукт который может добавлять опции типа (recompile) и т.п. А что касается вашего случая то вы должны обратить внимание при Hash join на оперативную память которую потребляет запрос. Сталкивался с ситуацией когда подобных запросов было очень много в единицу времени и сервер принимал решение переходить в долгие вложенные циклы. А была ситуация совокупностью факторов, одним из которых было объединение по ключу с индексированной строкой (255) в которой максимальные значения были до 10-и символов. По сути решением проблемы стало сокращение размерности поля. ... |
|||
:
Нравится:
Не нравится:
|
|||
16.09.2019, 13:41 |
|
Почему так сильно различаются планы запроса с Option(recompile) и без? И как это побороть?
|
|||
---|---|---|---|
#18+
AlxOlm, можно просто план закрепить ... |
|||
:
Нравится:
Не нравится:
|
|||
16.09.2019, 13:45 |
|
Почему так сильно различаются планы запроса с Option(recompile) и без? И как это побороть?
|
|||
---|---|---|---|
#18+
AlxOlm, никак не решилось. Взял распечатку топика, пошел к лидеру разработчиков и сказал - "идете на... юг" (прошу прощения за географические подробности). Я не разработчик, я dba, мне - простительно. ... |
|||
:
Нравится:
Не нравится:
|
|||
16.09.2019, 14:14 |
|
Почему так сильно различаются планы запроса с Option(recompile) и без? И как это побороть?
|
|||
---|---|---|---|
#18+
uaggster AlxOlm, никак не решилось. Взял распечатку топика, пошел к лидеру разработчиков и сказал - "идете на... юг" (прошу прощения за географические подробности). Я не разработчик, я dba, мне - простительно. ... |
|||
:
Нравится:
Не нравится:
|
|||
29.06.2020, 12:22 |
|
|
start [/forum/topic.php?fid=46&gotonew=1&tid=1685943]: |
0ms |
get settings: |
10ms |
get forum list: |
13ms |
check forum access: |
3ms |
check topic access: |
3ms |
track hit: |
54ms |
get topic data: |
7ms |
get first new msg: |
7ms |
get forum data: |
3ms |
get page messages: |
59ms |
get tp. blocked users: |
1ms |
others: | 13ms |
total: | 173ms |
0 / 0 |