Режим разделения итогов... #448994


#0 by rsv
Этот режим поднимает допполе _splitter  в таблицах итогов регистров. И в разрезе этого поля конкурирующщие транзакции параллелят записи в таблицы итогов. Режим управления блокировками на самой конфе выставлен в управляемый т.е. хинта serializable нет в движковых инструкциях и все выполняется в изоляции read commetted. На документах стоит запрет автоматического очищения движений.В базе никого нет. Менеджер блокировок 1С не задействован. Используется только регистр бухгалтерии. Мануал пишет что две конкурирующие транзакции при записи наборов в регистр будут делать это параллельно. Все бы ничего...но прежде чем собственно начинать записать набор в регистр необходимо его очистить пустым набором по регистратору. Так вот если раннее по этому регистратору ничего в регистре небыло ,транзакции действительно параллелятся . Все меняется когда по регистратору есть записи и  надо 1.сначала записать с пустым набором чтобы вчсе почистить по регистратору 2.потом собственно записать с непустым Итак допустим проводим документ 1 у него уже есть движения. Стопорим транзакцию после выполнения  записи пустого набора в отладчике. Смотрим в sp_lock и видим ворох блокировок X в том числе на таблицах тоталов после движковых инструкций update. Запускаем 2 документ. Смотрим что он натворил. А вот он как таки не может проапдейтить тоталы т.к. пытется блокирнуть такой же ресурс в тотале как и  первый документ. Собственно к чему этот трактат. Какая собственно разница пишу ли я пустой набор (для очистки по регситратору) или нормальный набор ?? Сплиттер должен разрулить и пустой набор распараллелить и непустой. Если у кого есть какая либо инфа более подробная чем в мануале о сплиттерах как он заполняется и как используется в запросах и с чем его есть буду признателен.  Профайлер не предлагать :)
#1 by rsv
Апну. Может кто прочтет. :)
#2 by mikecool
прочем, много думал :) так глубоко не копал
#3 by fisher
На правах идеи. Попробуй проанализировать типы блокировок, которые SQL на total накладывает. Там только на записи блокировки или не только? Может, сиквел эскалацию блокировок делает...
#4 by rsv
Там монопольные и на запись READ и на ключ КEY и  блокировки намерений . Ворошок целый. Собственно вычислил конкретную запись в таблице итогов по корреспонденции. Но это не дает картины общей  в целом. Инфы мало читабельной. Хочу в голове картинку общу поведенческую сложить по движковой запси в таблицы итогов.
#5 by fisher
Странно. По ключу ж вроде не должно быть блокировок...
#6 by МихаилМ
укажите  версию 1С:Предприятия
#7 by Bober
есть идея лучше, запиши набор записей и выполняй проверки по регистру. +ы один раз пишешь не требуется переправлять лишние данные через и соединения в запросе, по сути почти все есть в наборах.
#8 by rsv
Апнусь. Копал эту тематику  довольно долго . И вот  некотрые результаты. Прежде всего поправлюсь в не READ ,а RID конечно. И так.  Если есть движения у документа по регистрам , и он проводится то он сначала все чистит то ли через автоматическое удаление движений , то ли пустым набором это как разработчику будет удобно и это понятно  . Допустим первая транзация начала это действо по проведению и остановим ее в процедуре ПриЗаписи модуля набора записей регистра... ну к примеру бухгалтерии.  Запускаем sp_lock и видим  монопольные блокировки значения ключа индеса (KEY) таблицы движений,таблицы значений субконто,таблnицы итогов и оборотов по счету,одной из таблиц итогов c субконто (скажем используем счета в наборе у котрых по два субконто), а вот в таблице корреспондирующих счетов  AccTtlC  такую картину не наблюдаем не смотря на то что там ажно целых два составных неуникальных некластерных индеса. Там  мы наблюдаем  монопольную блокировку записи RID . И вот если запустить вторую транзакцию в другой сессии то по всем таблицам нормуль , splitter все разруливает а вот как раз на таблице корреспонденций  не хотит ничего делать и встает транзакция в статус wait на этой самой блоировке записи первой транзакции. Пытается наложить блокировку обновления U и ждет.... и отваливается. В принципе этой ситуации быть не должно т.к. во второй транзакции при обращении к таблице корреспонденций в разрезе уникального значения сплиттера должена быть просто всатвка с коррекцией. Но ......... Связываю с тем , что первая транзакция когда апдейтит таблицу AccTtlC всеж должна накладывать блокировку (как и на другие таблицы) по значению ключа индекса , а не явно записи в таблице. Получается что вторая транзакция в этом случае не может задейстовать сплиттер т.к. блокировка не по ключу (чисто мое предположение т.к. информации по работе сплиттера нет никакой статья общего характреа на ИТС не рассматривается). Связываю с неоптимальным планом конструкции update c join ом к таблице AccTtlC в первой транзакции что приводит к блокировке RID а не KEY. UPDATE _AccTtlC11756_T SET _Fld11735 = CAST(_AccTtlC11756_T._Fld11735 + #PRecords_R._Fld11735 AS NUMERIC(21,2)), _Fld11736Dt = CAST(_AccTtlC11756_T._Fld11736Dt + #PRecords_R._Fld11736Dt AS NUMERIC(21,2)), _Fld11736Ct = CAST(_AccTtlC11756_T._Fld11736Ct + #PRecords_R._Fld11736Ct AS NUMERIC(21,2)), _Fld11737Dt = CAST(_AccTtlC11756_T._Fld11737Dt + #PRecords_R._Fld11737Dt AS NUMERIC(21,3)), _Fld11737Ct = CAST(_AccTtlC11756_T._Fld11737Ct + #PRecords_R._Fld11737Ct AS NUMERIC(21,3)) FROM #tt10 #PRecords_R WITH(NOLOCK) INNER JOIN _AccTtlC11756 _AccTtlC11756_T ON #PRecords_R._Period = _AccTtlC11756_T._Period AND #PRecords_R._AccountDtRRef = _AccTtlC11756_T._AccountDtRRef AND #PRecords_R._AccountCtRRef = _AccTtlC11756_T._AccountCtRRef AND #PRecords_R._Fld11733RRef = _AccTtlC11756_T._Fld11733RRef AND (#PRecords_R._Fld11734DtRRef = _AccTtlC11756_T._Fld11734DtRRef OR #PRecords_R._Fld11734DtRRef IS NULL AND _AccTtlC11756_T._Fld11734DtRRef IS NULL) AND (#PRecords_R._Fld11734CtRRef = _AccTtlC11756_T._Fld11734CtRRef OR #PRecords_R._Fld11734CtRRef IS NULL AND _AccTtlC11756_T._Fld11734CtRRef IS NULL) AND _AccTtlC11756_T._Splitter = CAST(0. AS NUMERIC(1,0)) План посомтреть не могу т.к. все update к тоталам идут в связке с временной таблицей.  Кто что скажет ? Какие мысли ? И как всеж план посмотреть когда временная таблица в запросе ? Релиз двигла 8.1.14.72. Регистр бухгалетрии не пустой . Тыщ 200 в движениях . MS SQL 2005 9.0.2047. В базе никого нет. Экперимент чистый.
#9 by fisher
Интересное исследование, сенк. Я правильно понял, что AccTtlC блокируется на запись ВСЯ?
#10 by fisher
Чтобы план посмотреть, наверное придется дублировать структуру и наполнение временной таблицы. Проблема скорее всего в том, что не один из индексов по какой-то причине не используется. Надо копать план запроса и пробовать варианты...
#11 by rsv
Блокируется именно конкретно запись  в таблице.RID Вторая транзакция пытается на этот же ресурс т.е. строку наложить X но не может конечно сразу и делает попытку ставить U. Об этом и речь. При выполнении запроса на update выше в первой транзакции используется план который  не задействует индексы а тупо по стоимости наверное принимает решение  сразу запись в таблице.  А вторая при таком раскладе не понимает что нужно применять сплиттер и параллелить. Вероятно не заточен сервер приложений управляющий режимом сплиттера видеть блокировку строки. Ему нужна гранулярность на уровне ключа индекса.  Догадки одни. Нужно конечно добиваться чтобы update в первой транзакции накладывал блокировку KEY. Возможно оптимизатору не хватает статистики или еще чего. Буду экспериментировать.
#12 by Aleksey_3
*закладка*
#13 by rsv
По русски ?
#14 by Aleksey_3
По русски тема тоже интересно, и чтобы проще было ее найти оставил сообщения. В последствие через "Темы с моим участием" проще найти
#15 by fisher
А! Т.е. в этой таблице просто сплиттер не работает, получается? И в итоге с одинаковыми корреспонденциями одновременно хрен проведешь? Тады дело не в сиквеле и не в его блокировках. Это платформа виновата.
#16 by IamAlexy
подпишуся
#17 by rsv
Пытаюсь пойти от обратного. Сплиттер не работает потому , что нет блокировки KEY.
#18 by fisher
Перечисли, плиз, какие поля входят в эту таблицу (прикладное значение, а не реальные названия). А то толстая книга не под рукой...
#19 by Lama12
/закладка/
#20 by rsv
Всем доброй ночи.Дкопался всеж до точки. Предположения в   в части того что вторая транзакция не поднимает сплиттер по причине не того типа блокировки оказались легким бредом :)  Сплиттер работает на пять с плюсом  ну и ни как не зависит от типа блокировки как оказалось. Да и не должен.   Отвлеку ваше внимание еще разок.  И так напомню , что исследуется  ситуация когда есть два документа одного вида  второй сделан копией с первого т.е. совершенно одинаковые. Да в принципе эта одинаковость до лампочки. Не суть . Т.е. есть два дока  они проведены и имеют движения по регистру бухгалтерии. 1.    Проводим первый документ т.е. начинаем первую транзакцию. Стопорим ее в отладчике в процедуре ПриЗаписи модуля набора записей регисттра бухгалтерии после того как записали пустой набор. Смотрим в профайлер .  Движок, для коррекции таблицы корреспонденций, вызывает конструкцию в . Обратите внимание что поле _splitter  в условии запроса запроса равно 0.  В части блокировок как и писал выше  update в вызовет блокировку  записи таблицы корреспонденций . rid. 2.    Проводим второй документ.Т.е. начинаем вторую транзакцию. Нигде ее не стопорим , да  и не можем т.к. отладчика один экземпляр может быть всего запущен. Да нам это инее надо. Вот тут то и начинает работать восьмерошный сплиттер. Определяется что что вторая транзакция конкурирует с первой (как и каким образом  неустановленно пока да и подзабъем пока на это. Главное что определяется)  по доступу к  ресурсам таблицы корреспонденций  (как в прочем и к другим) и сервер приложений генерит абсолютно такойже запрос  как в   но с условием что поле _splitter=2. Т.е. как по диску ИТС некая хешфункция двигла сгенерила в рамках конкуренции уникальное значение сплиттера. Вот  именно запрос второй транзакции на update таблицы корреспонденций и будет висеть.  Спрашивается какого он висит ???? Ведь в певрой транзакции условие в запросе _splitter=0 а во второй 2  ????????? Почему второй запрос пытается наложить монопольную блокировку на строку таблицы где значение  поля сплиттер равно 0   ????  Тут без плана запроса как без бутылки не разобраться. Пришлось набивать временную таблицу и моделировать всю цепочку в обычной сессии менеджемнт студио.  И после просмотра плана все вопросы отпали. В плане запроса видим обычный Table Scan по таблице корреспонденций и  Table Scan по верменной таблице. Временая таблиуа нас не интересует. Как она сканится до лампочки. А вот что сканится полностью  таблица корреспонденций котрую мы будем корректировать это плохо. Т.е. перебираются все строки таблицы и естественно идет затык на уже заблокированной строчке первой транзакцией.   Что делать ???  Попробуем подсказать запросу какой план выполнения выбрать. Используем предложение OPTION c аргументом  FORCE ORDER т.е option (force order) по русски это подсказка оптимизатрору , что при оптимизации запроса сохраняется порядок объединения, заданный синтаксисом запроса. К запросу в добавляем в конец option(force order). Смотрим план ……. И ураааааааа Видим не table scan , а  Index Seek .  И запрос прокатывает только на ура. Смотрм sp_lock а там две красивые блокировки red. Одна  сделанная первой транзакцией на сою запись. А вторая сделанная второй транзакцией на свою. Таким образом (сугубо имхо) что план запроса в приводит к  table scan , а с подсказкой к index  seek и выполняется без проблем. Вот такие вот дела.  За ошибки и корявость извеняйте.
#21 by fisher
Хм... А твои 200 тыщ движений по реальным данным набиты? Не тупыми копиями одного и того же? Может селективность индексов низкая или просто статистику в SQL забыл проапдейтить?
#22 by rsv
Реальными конечно. Самыми что ни на есть.
#23 by fisher
Если обновление статистики не помогает и такая картина на всех последних версиях сиквела с последними апдейтами, то ... Отпишись 1С, может в будущем поправят.
#24 by fisher
+ Так как индексы этой таблицы некластерные, то сиквел, видать, в большинстве случаев считает их использование слишком накладным (получение данных по некластерному индексу в самом деле небыстрая операция по меркам сиквела). И ему невдомёк, что при этом херится вся идея :)
#25 by rsv
Надо закругляться :).Ну что скзать. Все реиндексации , дефрагментации ... картинку не изменили. На чистом девелопере и на стандарте со 2-м сервис паком результат один и тот же. Вопрос ? Как лечить. Есть два пути . Первый по мануалу SQL 2005 где разработчик вводит специальную системную хранимую процедуру sp_create_plan_guide позволяющую перехватывать от приложения запросы и задавать подсказки опртимизатору. Все хооршо но... все апдейты к тоталам двигло делает с джойном с временной таблицей. Т.к. в хранимке одним из параметров  является собственно сам текст запроса то... если  в каждой сессии имя этой временной таблицы будет разной  или #t10 или #t12 или #N....  то плодить этот зоопарк не целесообразно. Ну что поделать если приложение генрит апдейт в связке с временной таблицей. Второй путь он более  предпочтителен и менее геморный. Собственно просто ... добавить ишо один индекс в таблицу тоталов корреспонденций счетов. Беглый анализ показвает что все таблицы тоталов имеют всего лишь один индекс. Он кластерный . Исключение составляет только таблица тоталов корреспондеций. Там два индекса и оба они не кластерные.  Добавил я в студио еще один индекс к этой таблице . Сделал его кластерным и уникальным. Перечень полей взял из одинэсовского некластерного индекса на эту таблицу _AccTtЦифрыИмяТаблицыТоталовКорреспонденций_ByDt_TRRRRRRRN. Погонял на профилировщике и все стало очень гуд. Блокировки ложаться не строки а на ключи. И запрос на апдейт работает исключительно на index seek по этому нововведенному индексу. Так что решение в добавлении еще одного индекса ( кластерного и уникального ) в конкретном случае полностью решает проблему. Погонял по мере возможности движковые конструкции в профайлере на записях пустых наборов регистра бухгалтерии. Все отрабатывают только по index seek. Это очень и очень гуууд.
#26 by acsent
спроси на форуме 1с, может кто из разрабов прокоментирует
Тэги:
Ответить:
Комментарии доступны только авторизированным пользователям

В этой группе 1С