Этот баннер — требование Роскомнадзора для исполнения 152 ФЗ.
«На сайте осуществляется обработка файлов cookie, необходимых для работы сайта, а также для анализа использования сайта и улучшения предоставляемых сервисов с использованием метрической программы Яндекс.Метрика. Продолжая использовать сайт, вы даёте согласие с использованием данных технологий».
Политика конфиденциальности
|
|
|
Оптимизация запроса с LEFT JOIN
|
|||
|---|---|---|---|
|
#18+
Добрый день, уважаемые коллеги. Бьюсь с запросом и Есть вопрос, связанный с оптимизацией и скоростью выполнения одного запроса. Прошу помощи у более опытных коллег. Исходные данные: Есть 3 временные таблицы, у которых есть такие индексы индексы. Код: plaintext 1. 2. 3. Есть такой запрос Код: plaintext 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. И есть такой план выполнения этого запроса Код: plaintext 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. 44. 45. 46. 47. 48. 49. 50. 51. 52. 53. 54. 55. 56. 57. 58. Если я всё правильно понимаю то здесь сервер выполняет один проход по таблице HHH что верно. Но для каждой строки внешней таблицы #HHH происходит по одному сканированию вложенной таблицы, пусть даже с позиционированием по индексу. Проблема в том, что при 84148 строках в таблице #HHH и 36963 в таблице #AAA и 84148 в таблице #CCC (и ещё аналогично присоединяют 2 таблицы, но я из здесь опустил). Запрос этот выполняется очень долго (в процентном соотношении это 80% времени всего задания), поэтому есть желание узнать можно ли его ускорить. Мне кажется тут бы можно было обойтись слиянием - зачем тут вложенные циклы ? Или это возможно только при кластерном индексе? Как думаете, можно ли тут что-то улучшить и если да то что? Спасибо! ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 19.12.2007, 15:33 |
|
||
|
Оптимизация запроса с LEFT JOIN
|
|||
|---|---|---|---|
|
#18+
Да, забыл сказать. Код: plaintext 1. 2. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 19.12.2007, 15:38 |
|
||
|
Оптимизация запроса с LEFT JOIN
|
|||
|---|---|---|---|
|
#18+
salt пишет: > Как думаете, можно ли тут что-то улучшить и если да то что? Тут если SARG-ов быть не может, то и ничего не сделаешь. Только ограничить может быть как-то максимальный размер наборов данных в этих временных таблицах. Проверить разве что чтобы для JOIN-ов все индексы были и использовались. Да вроде с этим все ОК. Ну а в плане выставить вперед внутреннюю таблицу во внешнем JOIN-е нельзя. Значит, более ничего и не сделать. Posted via ActualForum NNTP Server 1.4 ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 19.12.2007, 16:41 |
|
||
|
Оптимизация запроса с LEFT JOIN
|
|||
|---|---|---|---|
|
#18+
salt пишет: > Мне кажется тут бы можно было обойтись слиянием - зачем тут вложенные > циклы ? У вас оно включено ? Включите явно. > Или это возможно только при кластерном индексе? Насколько я помню, при любом. Но вам-то можно и кластерные сделать индексы. > Как думаете, можно ли тут что-то улучшить и если да то что? Можно переписать на ANSI JOIN Syntax, но это производительности не поможет, поможет только читаемости. Можно попереставлять дочерние "парралельные" таблицы, с force plan-ом. Но если у вас scan count не прыгает вверх-вниз во время посл. выполнения NLJ, то и не надо этого. А так - 85 тыщ записей просто не мало, вот и долго обрабатывается. Posted via ActualForum NNTP Server 1.4 ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 19.12.2007, 16:45 |
|
||
|
Оптимизация запроса с LEFT JOIN
|
|||
|---|---|---|---|
|
#18+
Да, все индексы вроде как используются. У меня есть жгучее подозрение что можно тут обойтись одним сканированием каждой таблицы. Будь я оптимизатором запросов - я бы шёл потихоньку по первой таблице одновременно хватая данные из других таблиц по условию соединения и присовокупляя их к результирующей. Очевидно - один проход по всем таблицам. Не могу ухватить что тут нужно - может данные чтобы были расположены в порядке сортировки... ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 19.12.2007, 16:54 |
|
||
|
Оптимизация запроса с LEFT JOIN
|
|||
|---|---|---|---|
|
#18+
MasterZiv salt пишет: > Мне кажется тут бы можно было обойтись слиянием - зачем тут вложенные > циклы ? У вас оно включено ? Включите явно. А как, к стыду признаюсь не знаю пока. Кстати, вообще в оригинале стоит Код: plaintext MasterZiv > Или это возможно только при кластерном индексе? Насколько я помню, при любом. Но вам-то можно и кластерные сделать индексы. > Как думаете, можно ли тут что-то улучшить и если да то что? Можно переписать на ANSI JOIN Syntax, но это производительности не поможет, поможет только читаемости. Можно попереставлять дочерние "парралельные" таблицы, с force plan-ом. Но если у вас scan count не прыгает вверх-вниз во время посл. выполнения NLJ, то и не надо этого. А так - 85 тыщ записей просто не мало, вот и долго обрабатывается. scan count вроде не прыгает. Таблицы перечислены так как есть, в оригинале запрос с forceplan-ом в ХПшке. 85 тыщ это на тестовом сервере. А получил я это задание с диагнозом "This never finishes on production" Сколько там данных в реальности не знаю - но думаю не меньше уж точно. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 19.12.2007, 17:02 |
|
||
|
Оптимизация запроса с LEFT JOIN
|
|||
|---|---|---|---|
|
#18+
Попробуйте разобраться с разницей между разными базовыми типами джойнов - Nested Loop Join, Sort-Merge Join, Hash Join. Как они работают и сколько сканирований каких таблиц делается в каждом типе джойна. Потом уже можно будет посмотреть а какие типы поддерживаются в 12.5.3 и что соответственно можно сделать. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 19.12.2007, 18:19 |
|
||
|
Оптимизация запроса с LEFT JOIN
|
|||
|---|---|---|---|
|
#18+
salt wrote: > У меня есть жгучее подозрение что можно тут обойтись одним сканированием > каждой таблицы. Ыыы. Если делать sort-merge-join - то да. > Будь я оптимизатором запросов - я бы шёл потихоньку по первой таблице > одновременно хватая данные из других таблиц по условию соединения и > присовокупляя их к результирующей. Очевидно - один проход по всем > таблицам. Не могу ухватить что тут нужно - может данные чтобы были Так так и делается почти. Только дочерние таблицы проходятся по N раз, но быстро, путем позиционирования по индексу. Стоимость последнего - O(log N) где N - размер этой таблицы. Не думаю что это у вас очень долго. Можете посчитать сами примерные стоимости двух вариантов выполнения запросов (оптимизатор считает не так, но не важно, просто чтобы сравнить) для SMJ: N1 + N2 + N3 + ... Nn ( где Ni - размер i-ой таблицы в записях) для NLJ: N1 * log(N2) * log(N3) .... * log(Nn) ( где Ni - размер i-ой таблицы в записях) И посмотрите, что получится выгоднее, хотя бы на таком примитивном расчете. Логарифмы можете брать по основанию 10, но это не важно. > расположены в порядке сортировки... Так они у вас и так "в порядке сотрировки" за счет индексов. Posted via ActualForum NNTP Server 1.4 ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 19.12.2007, 22:00 |
|
||
|
Оптимизация запроса с LEFT JOIN
|
|||
|---|---|---|---|
|
#18+
salt wrote: > А как, к стыду признаюсь не знаю пока. Либо включить в настройках сервера (если оно включено- ничего не делать), либо в сессии - set sort merge on go (в процедуре - go не надо, просто поставить в начало). > scan count вроде не прыгает. > Таблицы перечислены так как есть, в оригинале запрос с forceplan-ом в ХПшке. дело в том, что стоимости выполнения выдаются в порядке, который задан в запросе. Вам нужно упорядочить стоимости по порядку, в котором таблицы идут в плане запроса и посмотреть, прыгает ли scan count вверх на какой-то таблице, а потом обратно вниз. Если прыгает, то таблицу, на которой он идет вниз, можно продвинуть вперед по плану - чем раньше она обрубит записи, тем лучше. Но у вас наверное все же с этим все ОК. > А получил я это задание с диагнозом "This never finishes on production" > Сколько там данных в реальности не знаю - но думаю не меньше уж точно. Блин, такое не на реальных данных вообще нет смысла оптимизировать. Тут гадать нельзя. Posted via ActualForum NNTP Server 1.4 ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 19.12.2007, 22:06 |
|
||
|
Оптимизация запроса с LEFT JOIN
|
|||
|---|---|---|---|
|
#18+
up wrote: > Попробуйте разобраться с разницей между разными базовыми типами джойнов > - Nested Loop Join, Sort-Merge Join, Hash Join. Как они работают и Разве у нас уже есть Hash Join ? С какой версии ? > сколько сканирований каких таблиц делается в каждом типе джойна. Потом > уже можно будет посмотреть а какие типы поддерживаются в 12.5.3 и что Там есть только Loop Join, Sort-Merge Join Posted via ActualForum NNTP Server 1.4 ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 19.12.2007, 22:08 |
|
||
|
Оптимизация запроса с LEFT JOIN
|
|||
|---|---|---|---|
|
#18+
план запроса который вы привели - реальный план из хранимой процедуры или вы выдернули запрос оттуда и выполнили его отдельно? индексы на временные таблицы случайно не в той же хранимой процедуре создаются? ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 20.12.2007, 02:38 |
|
||
|
Оптимизация запроса с LEFT JOIN
|
|||
|---|---|---|---|
|
#18+
rcryoплан запроса который вы привели - реальный план из хранимой процедуры или вы выдернули запрос оттуда и выполнили его отдельно? индексы на временные таблицы случайно не в той же хранимой процедуре создаются? Всё верно, я выдернул запрос оттуда и выполнил отдельно. Временные таблицы и их индексы тоже создаются в той же хранимой процедуре (что логично). Это может существенно влиять ? ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 20.12.2007, 09:12 |
|
||
|
Оптимизация запроса с LEFT JOIN
|
|||
|---|---|---|---|
|
#18+
MasterZiv salt wrote: > У меня есть жгучее подозрение что можно тут обойтись одним сканированием > каждой таблицы. Ыыы. Если делать sort-merge-join - то да. > Будь я оптимизатором запросов - я бы шёл потихоньку по первой таблице > одновременно хватая данные из других таблиц по условию соединения и > присовокупляя их к результирующей. Очевидно - один проход по всем > таблицам. Не могу ухватить что тут нужно - может данные чтобы были Так так и делается почти. Только дочерние таблицы проходятся по N раз, но быстро, путем позиционирования по индексу. Стоимость последнего - O(log N) где N - размер этой таблицы. Не думаю что это у вас очень долго. Можете посчитать сами примерные стоимости двух вариантов выполнения запросов (оптимизатор считает не так, но не важно, просто чтобы сравнить) для SMJ: N1 + N2 + N3 + ... Nn ( где Ni - размер i-ой таблицы в записях) для NLJ: N1 * log(N2) * log(N3) .... * log(Nn) ( где Ni - размер i-ой таблицы в записях) И посмотрите, что получится выгоднее, хотя бы на таком примитивном расчете. Логарифмы можете брать по основанию 10, но это не важно. Но при таком расчёте если хотя бы одна таблица имеет всего 1 строку то NLJ будет 0. Посчитал, примерно. При десяти тысячах Ni в 3 таблицах получается что NLJ больше в 5 раз. И при росте N1 и прочих равных NLJ растёт быстрее чем SMJ ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 20.12.2007, 09:27 |
|
||
|
Оптимизация запроса с LEFT JOIN
|
|||
|---|---|---|---|
|
#18+
salt wrote: > Но при таком расчёте если хотя бы одна таблица имеет всего 1 строку то > NLJ будет 0. Ну формула -то на иднексы расчитана. Грубая она, да, ну да это же и ОЦЕНКА, а не точное время или стоимость. При 1 строке на самом деле индексы никогда не применяются, поэтому и логарифма не будет. > Посчитал, примерно. > При десяти тысячах Ni в 3 таблицах получается что NLJ больше в 5 раз. > И при росте N1 и прочих равных NLJ растёт быстрее чем SMJ Так я что=то и не понял, вы его (SMJ) включали ? Пробовали ? Posted via ActualForum NNTP Server 1.4 ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 20.12.2007, 10:42 |
|
||
|
Оптимизация запроса с LEFT JOIN
|
|||
|---|---|---|---|
|
#18+
salt wrote: > Всё верно, я выдернул запрос оттуда и выполнил отдельно. > Временные таблицы и их индексы тоже создаются в той же хранимой > процедуре (что логично). > Это может существенно влиять ? Да нет. Вы только проверьте план запроса и в процедуре тоже, чтобы быть уверенным, что индексы и в процедуре тоже используются. Posted via ActualForum NNTP Server 1.4 ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 20.12.2007, 10:43 |
|
||
|
Оптимизация запроса с LEFT JOIN
|
|||
|---|---|---|---|
|
#18+
MasterZiv salt wrote: > Всё верно, я выдернул запрос оттуда и выполнил отдельно. > Временные таблицы и их индексы тоже создаются в той же хранимой > процедуре (что логично). > Это может существенно влиять ? Да нет. Вы только проверьте план запроса и в процедуре тоже, чтобы быть уверенным, что индексы и в процедуре тоже используются. Хм. Да, действительно, в процедуре индексы не стали использоваться почему то. Вот кусок плана, взят из плана всей процедуры. Код: plaintext 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. 44. 45. 46. 47. 48. 49. 50. 51. 52. 53. 54. 55. 56. 57. 58. 59. 60. 61. 62. 63. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 20.12.2007, 15:40 |
|
||
|
Оптимизация запроса с LEFT JOIN
|
|||
|---|---|---|---|
|
#18+
salt wrote: > Да, действительно, в процедуре индексы не стали использоваться почему то. Тогда у вас два варианта. Либо создавать индексы ПОСЛЕ набивки таблицы данными, в таком случае статистика по ним будет уже реальная, либо писать хинты. Хинты для индексов на временные таблицы характерны тем, что имени индекса в (index xxxx) написать нельзя - имени постоянного у индекса нет. Поэтому надо индексы указывать по номерам. Номер индекса при этом - это идентификатор его в sysindexes (indid), он равен 0 - для самой таблицы (APL без кластерного индекса), 1 - для кластерного индекса APL (т.е. это APL с кластерным индексом) >1 - для всех остальных. Если у вас индекс один, то он будет либо 1, либо 2, в зависимости от того, APL у вас или DOL. Если что можно посмотреть в sysindexes. Posted via ActualForum NNTP Server 1.4 ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 20.12.2007, 17:07 |
|
||
|
Оптимизация запроса с LEFT JOIN
|
|||
|---|---|---|---|
|
#18+
Кажется странным, что ни один из индексов не используется. Добавьте in параметр @debug и добавьте логику, при @debug = 1 выводить отладочную информацию, в т.ч. подтверждение о создании индексов, количество записей в ваших таблицах, время выполнения запросов наполняющих временные таблицы и проч и проч. Зная реальное количество записей проще будет понять причину построения того или иного плана запроса. Удачи. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 20.12.2007, 17:13 |
|
||
|
Оптимизация запроса с LEFT JOIN
|
|||
|---|---|---|---|
|
#18+
KruКажется странным, что ни один из индексов не используется. это фича ;) надо создавать объекты в отдельных батчах - мухи отдельно, котлеты отдельно ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 20.12.2007, 17:30 |
|
||
|
Оптимизация запроса с LEFT JOIN
|
|||
|---|---|---|---|
|
#18+
авторКажется странным, что ни один из индексов не используется ничего странного, план процедуры строится при компиляции процедуры, а на этот момент индексов еще нет, поэтому и план получается такой. Навидался я такого кода, поэтому и спросил. Я бы не мудрил с хинтами, а вынес бы создание индексов во внешнюю процедуру и из нее бы уже вызывал эту процедуру с запросом и наверное лучше сделать эту процедуру с параметром WITH RECOMPILE. После этого все у вас будет хорошо. Да и на будущее если процедура долго выполняется смотрите реальный план всей процедуры а не отдельных запросов. Удачи. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 20.12.2007, 17:47 |
|
||
|
Оптимизация запроса с LEFT JOIN
|
|||
|---|---|---|---|
|
#18+
komrad wrote: > Кажется странным, что ни один из индексов не используется. > надо создавать объекты в отдельных батчах - мухи отдельно, котлеты отдельно Вовсе и не обязательно. У него современныс ASE, там и без этого должно работать. Posted via ActualForum NNTP Server 1.4 ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 20.12.2007, 18:15 |
|
||
|
Оптимизация запроса с LEFT JOIN
|
|||
|---|---|---|---|
|
#18+
rcryo wrote: > ничего странного, план процедуры строится при компиляции процедуры, а на > этот момент индексов еще нет, поэтому и план получается такой. Навидался > я такого кода, поэтому и спросил. При изменнеии схемы таблиц, используемых процедурой, планы должны пересоздаваться. Поэтому создавать таблицу в отдельной внешней процедуре в современном ASE вовсе не обязательно. Это вот если бы был древний какой-нибудь типа 11.9, там может быть это и имело смысл. > Я бы не мудрил с хинтами, а вынес бы создание индексов во внешнюю Проще уж помудрить с хинтами. Создавать такую процедуру будет не очень уж просто. > процедуру и из нее бы уже вызывал эту процедуру с запросом и наверное > лучше сделать эту процедуру с параметром WITH RECOMPILE. Это-то зачем ? WITH RECOMPILE как поможет ? WITH RECOMPILE заставляет процедуру перегенерировать планы запросов при каждом вызове, а не при первом когда плана нет в кэше. Чем это здесь поможет -то ? Posted via ActualForum NNTP Server 1.4 ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 20.12.2007, 18:20 |
|
||
|
Оптимизация запроса с LEFT JOIN
|
|||
|---|---|---|---|
|
#18+
rcryo авторКажется странным, что ни один из индексов не используется ничего странного, план процедуры строится при компиляции процедуры, а на этот момент индексов еще нет, поэтому и план получается такой. Навидался я такого кода, поэтому и спросил. Я бы не мудрил с хинтами, а вынес бы создание индексов во внешнюю процедуру и из нее бы уже вызывал эту процедуру с запросом и наверное лучше сделать эту процедуру с параметром WITH RECOMPILE. После этого все у вас будет хорошо. Да и на будущее если процедура долго выполняется смотрите реальный план всей процедуры а не отдельных запросов. Удачи. Если план строится при компиляции, то можно ли на него посмотреть сразу после компиляции? И как в таком случае поможет создание индексов во внешней процедуре - ведь для внутренней процедуры план уже построен при компиляции ? А, понял. WITH RECOMPILE заставляет перекомпилировать вложенную процедуру. Посмотрел сейчас в процедуры - действительно, существуют индексы которые, возможно, во внешних процедурах используются, но в тех в которых они создаются - они как видно не используются. Спасибо! ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 20.12.2007, 18:58 |
|
||
|
Оптимизация запроса с LEFT JOIN
|
|||
|---|---|---|---|
|
#18+
KruКажется странным, что ни один из индексов не используется. Добавьте in параметр @debug и добавьте логику, при @debug = 1 выводить отладочную информацию, в т.ч. подтверждение о создании индексов, количество записей в ваших таблицах, время выполнения запросов наполняющих временные таблицы и проч и проч. Зная реальное количество записей проще будет понять причину построения того или иного плана запроса. Удачи. Я похожим образом замерял временнЫе интервалы чтобы найти самые медленные участки в процедуре. Спасибо за идею, буду развивать. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 20.12.2007, 19:04 |
|
||
|
Оптимизация запроса с LEFT JOIN
|
|||
|---|---|---|---|
|
#18+
WITH RECOMPILE дает команду перекомпилить процедуру перед выполнением когда уже индексы созданы а также поможет также оптимизатору сориентироваться на реальных данных во временных таблицах на момент выполнения процедуры. В одной ситуации у вас там может быть примерно одинаковое количество записей, в другой - в соотношении 1:1000:1000000. тогда при любом соотношении будет выбран оптимальный план. авторЕсли план строится при компиляции, то можно ли на него посмотреть сразу после компиляции? Код: plaintext 1. MasterZivПри изменнеии схемы таблиц, используемых процедурой, планы должны пересоздаваться. У человека индексы создаются в той же процедуре что и выполняется запрос. У меня ASE 12.5.3 не использует такие индексы в запросах в той же процедуре авторСоздавать такую процедуру будет не очень уж просто. Вырезать запрос и поместить его в отдельную процедуру это очень не просто... ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 20.12.2007, 19:23 |
|
||
|
|

start [/forum/topic.php?fid=55&msg=35022531&tid=2011753]: |
0ms |
get settings: |
11ms |
get forum list: |
20ms |
check forum access: |
4ms |
check topic access: |
4ms |
track hit: |
95ms |
get topic data: |
13ms |
get forum data: |
3ms |
get page messages: |
87ms |
get tp. blocked users: |
2ms |
| others: | 270ms |
| total: | 509ms |

| 0 / 0 |
