План запроса SQL. Index Seek выполняется много раз и возвращает больше строк чем есть в таблице.

1. DmitriyTih 29.10.19 10:34 Сейчас в теме
Здравствуйте!
Помогите понять возникающую ситуацию. Есть задача - отчет для руководства. Есть постановщики задачи, которые меняются раз в полгода, год. Соответственно задача постоянно меняется. В связи с этим принято решение написать отчет так, чтобы можно было его достаточно быстро дорабатывать и он выполнялся в приемлемое время (до 2-х минут в зависимости от настроек).

Так вот с недавнего момента отчет, можно сказать, перестал работать. Один из запросов, который выполняется в цикле, начал вести себя странно, то выполняется за доли секунды, то выполняется 30 сек. Было принято решение посмотреть план запроса. В результате возникли вопросы, на которые хочется найти ответ, а работа с интернетом не дала результатов))).

К технической стороне:
Есть регистр сведений, в котором около 1 млн записей и каждый день происходит добавление около 1000 записей.
Есть запрос (в коде выполняется в цикле). Его суть - получить дату последней актуальной информации в регистре по контрагенту. В регистре есть еще измерения "Договор", "ИдентификаторДокумента".
"ВЫБРАТЬ ПЕРВЫЕ 1
| ПросроченнаяДебиторскаяЗадолженностьСрезПоследних.Период КАК Период,
| ПросроченнаяДебиторскаяЗадолженностьСрезПоследних.Организация,
| ПросроченнаяДебиторскаяЗадолженностьСрезПоследних.Контрагент
|ИЗ
| РегистрСведений.ПросроченнаяДебиторскаяЗадолженность.СрезПоследних(
| &Период,
| Организация = &Организация
| И Контрагент = &Контрагент) КАК ПросроченнаяДебиторскаяЗадолженностьСрезПоследних
|
|УПОРЯДОЧИТЬ ПО
| Период УБЫВ";

Когда запрос выполняется быстро - файл "План запроса быстро".
Когда запрос выполняется медленно - файл "План запроса медленно".

В двух словах при быстром выполнении Index Seek выполняется 1 раз и возвращает несколько сотен записей в зависимости от переданных параметров!
При медленном выполнении Index Seek выполняется, в приведенном примере, 3057 раз и возвращает > 26 млн записей! Хотя в таблице всего около 1 млн записей. Может кто подскажет, почему так происходит?
Прикрепленные файлы:
План запроса быстро.txt
План запроса медленно.txt
По теме из базы знаний
Ответы
Подписаться на ответы Инфостарт бот Сортировка: Древо развёрнутое
Свернуть все
2. nomad_irk 76 29.10.19 10:47 Сейчас в теме
(1) А можно узнать, для чего делать ВЫБРАТЬ ПЕРВЫЕ 1, обращаясь к СрезПоследних?
Дмитрий74Чел; +1 Ответить
10. DmitriyTih 29.10.19 11:00 Сейчас в теме
(2) Если не использовать, то запрос возвращает > 1 записи, т.к. отбор применяется не по всем измерениям
18. nomad_irk 76 29.10.19 11:04 Сейчас в теме
(10)Ух, все чудесатее.....Может не пытаться уже оптимизировать костыли, а переделать?
Дмитрий74Чел; +1 Ответить
21. DmitriyTih 29.10.19 11:06 Сейчас в теме
(18) это понятно, вопрос почему Index Seek выполняется, в приведенном примере, 3057 раз и возвращает > 26 млн. записей?
23. YannikAlx 43 29.10.19 11:07 Сейчас в теме
(18) Простые пути - для простачков! )))))
26. a.doroshkevich 1414 29.10.19 11:12 Сейчас в теме
28. DmitriyTih 29.10.19 11:13 Сейчас в теме
29. DmitriyTih 29.10.19 11:16 Сейчас в теме
(28)
(26) приветствую уважаемого специалиста!
37. a.doroshkevich 1414 29.10.19 13:23 Сейчас в теме
(29)
Дмитрий, помимо (33), я бы ещё глянул регламентное задание по обновлению статистики, выполняется ли и как часто.
Поскольку один и тот же запрос выполняется по разному, значит такой план выбирает планировщик.
Планировщик опирается на статистику.

Сброс процедурного кэша при чудесах в планах так же полезен, это команда DBCC FREEPROCCACHE - выполняется очень быстро, можно прям "наживую".

Приведите полную версию SQL, выполнив запрос select @@version, пожалуйста. Надо почитать есть ли в обновлениях для этой версии исправления ошибок по выбору плана.
39. DmitriyTih 29.10.19 13:30 Сейчас в теме
(37) Спасибо за ответ, с SQl мало знаком, но сейчас буду пытаться разбираться, насколько позволит время.
42. DmitriyTih 29.10.19 13:56 Сейчас в теме
(37) версия SQL: Microsoft SQL Server 2008 (RTM) - 10.0.1600.22 (X64) Jul 9 2008 14:17:44 Copyright © 1988-2008 Microsoft Corporation Enterprise Edition (64-bit) on Windows NT 6.1 <X64> (Build 7601: Service Pack 1)
33. wertep 23 29.10.19 11:32 Сейчас в теме
(1) А давайте посмотрим в сервер БД.
С какой периодичностью выполняется реорганизация и перестроение индексов?
Какой стоит Fill factor по умолчанию?
Параметр Max Degree of Parrallelism = 1.
a.doroshkevich; +1 Ответить
36. nomad_irk 76 29.10.19 12:08 Сейчас в теме
(33)
Max Degree of Parrallelism = 1

Один я пока не понимаю, по какой причине так делают в случае 1С для увеличения быстродействия?
38. a.doroshkevich 1414 29.10.19 13:26 Сейчас в теме
(36)
Вадим, так как 1С это почти всегда OLTP нагрузка (много маленьких транзакций на запись и чтение), поэтому почти всегда проигрыш на объединении результата распараллеленного запроса больше, чем выигрыш по скорости его выполнения относительно 1 ядра.

Например на 1 ядре запрос выполняется 1 сек
На 2-х ядрах 0,7 сек и на объединение результата этих 2-х ядер уходит ещё 0,5 сек, получаем проигрыш

Опять же, в каждой системе надо это тестировать, но общая рекомендация Max Degree of Parrallelism = 1
41. wertep 23 29.10.19 13:33 Сейчас в теме
(38) Плюсом ко всему выше сказанному.
1С генерит запросы по шаблону и не нет возможности их оптимизировать под конкретные потребности. как в системах где запросы пишутся на прямую к серверу БД.
И есть очень не маленькие шансы в таких случаях когда параллельные ветки одного запроса застревают на блокировках между собой.
44. nomad_irk 76 29.10.19 14:07 Сейчас в теме
(41)Для понимания:

Цитата1

Цитата2


Указывать MDOP = 1 - по крайне мере глупо, ИМХО.
46. wertep 23 29.10.19 16:30 Сейчас в теме
(44)
Для понимания:

Прекрасный опус, но как и вы можете заметить очень специфичный.
Поэтому для общей аудитории проще сделать так. А те кто понимают написанное вами, вопросов таких задавать не будут.
47. nomad_irk 76 29.10.19 16:33 Сейчас в теме
(46)Для общей аудитории глупо рекомендовать делать MDOP = 1.
43. nomad_irk 76 29.10.19 14:04 Сейчас в теме
(38)Так оно ж еще рулится по времени выполнения запроса, по-умолчанию - 5 с на запрос.
Если запрос выполняется меньше установленного времени и может быть распараллелен, то он не будет параллелиться.
48. a.doroshkevich 1414 29.10.19 17:46 Сейчас в теме
(43)Да, конечно
Но, по умолчанию в ms sql стоит значение 0, т.е. использовать все доступные ядра.
И мы можем получить ситуацию, когда один тяжелый запрос, длительностью выше порога (5 сек) просто положит весь сервер и остальные пользователи встанут в очередь.
Для oltp это плохой сценарий.
Можно долго об этом спорить, но:
1. Это является рекомендаций Фирмы 1С
2. Все большие и нагруженные системы нужно тестировать и принимать взвешенные решения по настройкам
49. nomad_irk 76 29.10.19 17:53 Сейчас в теме
(48)Будет правильнее установить границу времени выполнения больше 5с(10, 20....), вместо MDOP = 1.
52. a.doroshkevich 1414 29.10.19 18:53 Сейчас в теме
(49)Не только, но и подобрать значение mdop опять же для инсталляций где есть компетенции для правильного подбора и тестирования настроек.
40. DmitriyTih 29.10.19 13:32 Сейчас в теме
(33) Пока не могу ответить на вопросы) не специалист. сейчас буду изучать). Спасибо за совет!
50. Indgo 398 29.10.19 18:09 Сейчас в теме
(1)
"ВЫБРАТЬ ПЕРВЫЕ 1
| ПросроченнаяДебиторскаяЗадолженностьСрезПоследних.Период КАК Период,
| ПросроченнаяДебиторскаяЗадолженностьСрезПоследних.Организация,
| ПросроченнаяДебиторскаяЗадолженностьСрезПоследних.Контрагент
|ИЗ
| РегистрСведений.ПросроченнаяДебиторскаяЗадолженность.СрезПоследних(
| &Период,
| Организация = &Организация
| И Контрагент = &Контрагент) КАК ПросроченнаяДебиторскаяЗадолженностьСрезПоследних
|
|УПОРЯДОЧИТЬ ПО
| Период УБЫВ";


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

надо писать так
ВЫБРАТЬ ПЕРВЫЕ 1
| ПросроченнаяДебиторскаяЗадолженностьСрезПоследних.Организация,
| ПросроченнаяДебиторскаяЗадолженностьСрезПоследних.Контрагент
|ИЗ
| РегистрСведений.ПросроченнаяДебиторскаяЗадолженность.СрезПоследних(
| &Период,
| Организация = &Организация
| И Контрагент = &Контрагент) КАК ПросроченнаяДебиторскаяЗадолженностьСрезПоследних
| ";
Показать
55. DmitriyTih 30.10.19 09:36 Сейчас в теме
Цель была другая, не суть.
57. Дмитрий74Чел 234 21.11.19 10:30 Сейчас в теме
(1) задайте свой вопрос на https://www.sql.ru/forum/microsoft-sql-server и http://www.gilev.ru/forum/viewforum.php?f=15&sid=554a52b207e85a43fe7a71f9108478de
Только не пишите всю прелюдию - укажите только планы запросов.

P.s. но это не отменяет необходимости переписать отчет с листа.
3. AlexandrSmith 69 29.10.19 10:49 Сейчас в теме
Вообще конечно маловероятно что запрос косячит в SQL Server.

Нет ли у вас под рукой вероятного злоумышленника.

Может быть все не так просто, как кажется. Записи дополнительные могут добавляться по ходу работы.

Вы заметили что планы запросов в одном и другом случае совершенно одинаковы.
Значит все сводится к тому, что данные разные.

По крайней мере это видно из ваших планов запросов
16. DmitriyTih 29.10.19 11:03 Сейчас в теме
(3) Почему Index Seek выполняется, 3057 раз и возвращает > 26 млн. есть мысли Откуда 26 млн. записей?
20. YannikAlx 43 29.10.19 11:05 Сейчас в теме
(16) Запрос в цикле -ясно не табу! Но если есть способ обойти этот механизм, то стоит его всегда избегать.
Вы уверены, что не можете обойтись без запроса именно в цикле?
22. DmitriyTih 29.10.19 11:06 Сейчас в теме
(20) Все можно переделать. Это понятно, вопрос почему Index Seek выполняется, в приведенном примере, 3057 раз и возвращает > 26 млн. записей?
24. nomad_irk 76 29.10.19 11:09 Сейчас в теме
(16)Если Index Seek работает большое количество раз, значит поиск происходит по полям, не участвующим в образовании индекса, нет?
bocharovki; +1 Ответить
51. Indgo 398 29.10.19 18:24 Сейчас в теме
(3) Так Параметры же разные - если заказать итоги по дату рассчитанных итогов - то одно дело - Если середина месяца - то будет пересчет делать - вот тебе и разница
53. a.doroshkevich 1414 30.10.19 03:40 Сейчас в теме
(51)Если период в двух приведенных планах разный, то да.

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

Дмитрий, уточните, все ли параметры запроса одинаковые?
54. DmitriyTih 30.10.19 09:06 Сейчас в теме
(53) В примерах планов запросов, которые я привел, отличается только параметр "контрагент". Но когда проводил тестирование весь отчет мог выполняться около 30 сек в течение всего дня и по части планов запросов отличалось только количество возвращаемых строк Index seek (100-300 строк в зависимости от параметра "контрагент"). Потом резко начинал тупить и количество возвращаемых строк Index seek (2 млн - 30 млн строк в зависимости от параметра "контрагент"). Сначала пробовал перегружать агента SQL, помогало на день работы, потом понял что дело в чем то другом и полез в планы смотреть и т.п.
56. a.doroshkevich 1414 30.10.19 10:25 Сейчас в теме
(54) Ну тогда все рекомендации по SQL в силе
4. VmvLer 29.10.19 10:49 Сейчас в теме
В чем смысл конструкции:
|УПОРЯДОЧИТЬ ПО
| Период УБЫВ";
5. nomad_irk 76 29.10.19 10:50 Сейчас в теме
(4) Для работы Выбрать Первые N. В данном случае, выбирается последнее 1 значение по периоду.
7. RustamZz 29.10.19 10:53 Сейчас в теме
(5) Он одну строку возвращает хоть упорядочивай, хоть нет, Хоть Первые 1 хоть Первый 1000.
9. nomad_irk 76 29.10.19 10:58 Сейчас в теме
(7)Ну слава 1С: сперва сформируется срез последних с 1 строкой и потом наложится Первые 1 с упорядочиванием по периоду :)
15. DmitriyTih 29.10.19 11:02 Сейчас в теме
(9) Если не использовать, то запрос возвращает > 1 записи, т.к. отбор применяется не по всем измерениям
14. DmitriyTih 29.10.19 11:01 Сейчас в теме
(7) Нет запрос возвращает > 1 записи
6. RustamZz 29.10.19 10:51 Сейчас в теме
(4) Да весь этот запрос полная бессмыслица. И Выбрать первые 1 и упорядочить. Еще и в цикле выполняется.
8. nomad_irk 76 29.10.19 10:55 Сейчас в теме
(6)...да 1С тормозная и глючная....
13. DmitriyTih 29.10.19 11:01 Сейчас в теме
(6) Если не использовать, то запрос возвращает > 1 записи, т.к. отбор применяется не по всем измерениям.
Суть не в запросе, а в плане!
11. DmitriyTih 29.10.19 11:00 Сейчас в теме
(4) Если не использовать, то запрос возвращает > 1 записи, т.к. отбор применяется не по всем измерениям
17. YannikAlx 43 29.10.19 11:03 Сейчас в теме
(11) А вы не думали, отбор сделать по всем измерениям? Оно бы работало быстрее и проще ...
19. DmitriyTih 29.10.19 11:05 Сейчас в теме
(17) все верно, Там вообще надо из одного регистра делать 2 регистра. Суть в другом, почему Index Seek выполняется, в приведенном примере, 3057 раз и возвращает > 26 млн. записей, если в таблице их около 1 млн
32. nomad_irk 76 29.10.19 11:32 Сейчас в теме
(19)Потому что Index seek происходит по полям, не формирующим индекс и эти 26М записей - результат выполнения 3057 поисков, с результатом в 8505 строк на каждый в среднем.
34. DmitriyTih 29.10.19 11:42 Сейчас в теме
(32) может есть предположения, почему один раз запросы отрабатывают быстро, а при следующем запуске отчета медленно. Потом через какое-то время запросы опять работают быстро? "Внутрянка" SQL?
35. nomad_irk 76 29.10.19 11:59 Сейчас в теме
(34)Предположение пока одно: изменяется значения в индексе/статистика использования индексов не актуальная на момент "долгого" выполнения запроса.
12. YannikAlx 43 29.10.19 11:00 Сейчас в теме
(4) ну это же элементарно , Ватсон, - Чтоб шпионы не догадались , что мы тут вообще делаем..
25. YannikAlx 43 29.10.19 11:09 Сейчас в теме
(22) Вы напоминаете того мальчишку из Ералаша, который проверял -где пересекутся 2 параллельные прямые.
И все время уточнял другому товарищу - Да здесь не пересекаются... А дальше?!
27. DmitriyTih 29.10.19 11:13 Сейчас в теме
(25) Есть вопрос, интересно разобраться и найти ответ. В комментах многие пишут инфу не относящуюся к сути вопроса. Или я задал вопрос, на который все знают ответ?
30. YannikAlx 43 29.10.19 11:19 Сейчас в теме
(27) Вы поймите , вокруг очень много неясных вопросов, если заниматься каждым из них, можно вообще никогда не решить поставленную задачу.
Вам тут именно это пытаются донести.
Вы скорее всего пошли тупиковым путем, и уперлись в стену. Не нужно до помутнения рассудка разбираться кто построил стену и из чего она сделана, стоит просто вернутся и попробовать пойти другим путем. Возможно так вы доберетесь быстрее.
Если бы вы описали свою изначальную задачу , возможно кто-то смог бы помочь более продуктивно...
31. DmitriyTih 29.10.19 11:29 Сейчас в теме
(30)Спасибо за ответ. Дело в том, что я знаю как ее решить, просто хотел найти ответ на возникший вопрос, и не думал как все может быть сложно. С SQL до этого не работал, как и с анализом планов запроса.
triviumfan; +1 Ответить
58. triviumfan 93 24.12.19 13:54 Сейчас в теме
(31) покажите планы в формате xml/sqlplan.
И ещё раз проверьте какие параметры задаются.
ЗЫ: и структуру регистра в метаданных 1с и sql.
45. VmvLer 29.10.19 14:09 Сейчас в теме
Оставьте свое сообщение

Для получения уведомлений об ответах подключите телеграм бот:
Инфостарт бот