Имя: Пароль:
1C
1С v8
УПП взаимоблокировки на регистре партий при перепроведении
0 Sun_Storm
 
12.10.15
17:17
Добрый день!

Есть такая проблема в УПП: При перепроведении документов "Перемещение товаров" и "Реализация товаров и услуг" происходят взаимоблокировки.

В процессе расследования было выяснено, что взаимоблокировки возникают на регистре ПартииТоваровНаСкладах при чтении остатков.

У регистра включено разделение итогов.

Первая блокировка регистра ставится в момент удаления старых движений (удалять движения автоматически выключено).

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

Редакция УПП: 1.3.62.1 переписанная. Механизм типовой.

По идее, если после записи идет чтение, то для набора записей нужно ставить свойство БлокироватьДляИзменения, но при удалении движений оно не ставиться. Либо убрать у регистра свойство Разделение итогов. Однако смущает то, что такая проблема есть в типовом механизме.

Сталкивался ли кто-нибудь с такой проблемой? Если да, то как лучше решать? Может я чего-нибудь не учел и в УПП есть какая-то настройка на этот счет?
1 NcSteel
 
12.10.15
17:23
ну так двигай партии отдельно, зачем самой реализаций списывать и расчитывать партии.

А вообще Рауз форева
2 Гёдза
 
12.10.15
17:37
нужна упр блокировка ДО чтения остатков
3 Sun_Storm
 
12.10.15
19:58
(1) Был выбран именно онлайн расчет партий, ещё до меня, сейчас так работает. Тем более что механизм типовой.
(2) Да, это ещё один вариант исправить ситуацию. Сейчас базы под рукой нет, однако если там идет рассчет остатков, то управляемая блокировка все же должна быть до чтения остатков. Однако даже если она есть, то все равно при удалении движений будет блокировка СУБД части записей таблицы итогов (до удаления движения там никаких блокировок точно не ставится). Так что если только ставить управляемую блокировку ещё до удаления движений.

Получается, что сначала идет удаление движений - запись, потом чтение остатков, потом запись уже нового набора. А когда идет сначала запись, потом чтение, можно вроде как использовать свойство БлокироватьДляИзменения (если, конечно, проблема в блокировке именно по разделителю).

Кстати, между двумя документами ПеремещениеТоваров тоже идет такая взаимоблокировка. Они там все используют одни и те же процедуры для удаления движений и для чтения остатков.

Есть у кого-нибудь УПП с онлайн расчетом партий и типовым перемещением? Если открыть две сессии и поперепроводить там перемещения взаимоблокировки есть? Возможно есть какие-то галки, которые можно проставить и все будет работать, а я просто о них не знаю.

А так завтра попробую сначала поставить БлокироватьДляИзменения в истину/убрать разделитель и протестировать, если не получится, тогда буду писать управляемые.
4 РазДва
 
12.10.15
23:43
(3) очевидных проблем в типовой нет со взаимоблокировками, проблема может быть в том план запроса блокирует больший диапазон, чем номенклатура, которая в документе. Характеристики используются?
5 NcSteel
 
13.10.15
00:11
(3) Ну так отказывайтесь, как раз ты пришел и пришла пора думать головой и отказываться.
6 NcSteel
 
13.10.15
00:11
(4) В УПП? есть )))
7 Sun_Storm
 
14.10.15
10:01
В общем, основная проблема не в отсутствие упр. блокировок (хотя, конечно, блокировки надо будет поставить), а в не оптимальном запросе.

Итоговый запрос, который блокирует регистр при проверке остатков такой:
ВЫБРАТЬ
    ПартииТоваровНаСкладах.Номенклатура,
    ПартииТоваровНаСкладах.ДокументОприходования,
    ПартииТоваровНаСкладах.Склад,
    ПартииТоваровНаСкладах.ХарактеристикаНоменклатуры,
    ПартииТоваровНаСкладах.СерияНоменклатуры,
    ПартииТоваровНаСкладах.Качество,
    ПартииТоваровНаСкладах.Заказ,
    ПартииТоваровНаСкладах.КоличествоОстаток КАК Количество,
    ПартииТоваровНаСкладах.СтоимостьОстаток КАК Стоимость,
    ПартииТоваровНаСкладах.СтатусПартии
    
ПОМЕСТИТЬ ПартииТоваровНаСкладах
ИЗ
    РегистрНакопления.ПартииТоваровНаСкладах.Остатки(
        &Дат,
        Организация = &Организация
        И (Номенклатура, ХарактеристикаНоменклатуры) В (
                ВЫБРАТЬ
                    СписанныеТовары.Номенклатура,
                    СписанныеТовары.ХарактеристикаНоменклатуры
                ИЗ
                    РегистрСведений.СписанныеТовары КАК СписанныеТовары
                ГДЕ
                    СписанныеТовары.Регистратор = &Ссылка)
        И (Склад В (
                ВЫБРАТЬ
                    РегистрСведений.СписанныеТовары.Склад
                ИЗ
                    РегистрСведений.СписанныеТовары
                ГДЕ
                    РегистрСведений.СписанныеТовары.Регистратор = &Ссылка)
            ИЛИ Склад = &ПустойСклад)) КАК ПартииТоваровНаСкладах

ИНДЕКСИРОВАТЬ ПО
    Номенклатура,
    ХарактеристикаНоменклатуры,
    Качество,
    Склад,
    СтатусПартии,
    Заказ,
    СерияНоменклатуры
;

///////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
    СписанныеТовары.НомерСтрокиДокумента КАК НомерСтрокиДокумента,
    ПартииТоваровНаСкладах.Номенклатура,
    ПартииТоваровНаСкладах.ДокументОприходования,
    
    ПартииТоваровНаСкладах.Склад,
    ПартииТоваровНаСкладах.ХарактеристикаНоменклатуры,
    ПартииТоваровНаСкладах.СерияНоменклатуры,
    ПартииТоваровНаСкладах.Качество,
    ПартииТоваровНаСкладах.Заказ,
    ПартииТоваровНаСкладах.Количество,
    ПартииТоваровНаСкладах.Стоимость,
    ПартииТоваровНаСкладах.СтатусПартии,
    ВЫБОР
        КОГДА СписанныеТовары.СерияНоменклатуры = ПартииТоваровНаСкладах.СерияНоменклатуры
            ТОГДА 0
        ИНАЧЕ 1
    КОНЕЦ КАК ЧислоСерияНоменклатуры,
    ВЫБОР
        КОГДА СписанныеТовары.ДокументПартии = НЕОПРЕДЕЛЕНО
            ТОГДА 0
        ИНАЧЕ ВЫБОР
                КОГДА СписанныеТовары.ДокументПартии = ПартииТоваровНаСкладах.ДокументОприходования
                    ТОГДА 0
                ИНАЧЕ 1
            КОНЕЦ
    КОНЕЦ КАК ЧислоДокументОприходования,
    ВЫБОР
        КОГДА СписанныеТовары.ЗаказПартии = НЕОПРЕДЕЛЕНО
            ТОГДА 0
        ИНАЧЕ ВЫБОР
                КОГДА ПартииТоваровНаСкладах.Заказ = &ПустойЗаказ
                    ТОГДА 1
                ИНАЧЕ 0
            КОНЕЦ
    КОНЕЦ КАК ЧислоЗаказ,
    ВЫБОР
        КОГДА ПартииТоваровНаСкладах.СтатусПартии = &НаКомиссию
            ТОГДА 1
        ИНАЧЕ 0
    КОНЕЦ КАК ЧислоСтатусПартии
ИЗ
    РегистрСведений.СписанныеТовары КАК СписанныеТовары
        ВНУТРЕННЕЕ СОЕДИНЕНИЕ
            ПартииТоваровНаСкладах КАК ПартииТоваровНаСкладах
        ПО
            СписанныеТовары.Номенклатура = ПартииТоваровНаСкладах.Номенклатура
            И СписанныеТовары.ХарактеристикаНоменклатуры = ПартииТоваровНаСкладах.ХарактеристикаНоменклатуры
            И (ВЫБОР
                КОГДА ПартииТоваровНаСкладах.Качество = &ПустоеКачество
                    ТОГДА ИСТИНА
                ИНАЧЕ ВЫБОР
                        КОГДА СписанныеТовары.Качество = &ПустоеКачество
                            ТОГДА ПартииТоваровНаСкладах.Качество = &КачествоНовый
                        ИНАЧЕ ПартииТоваровНаСкладах.Качество = СписанныеТовары.Качество
                    КОНЕЦ
            КОНЕЦ)
            И (ПартииТоваровНаСкладах.Склад = СписанныеТовары.Склад ИЛИ ПартииТоваровНаСкладах.Склад = &ПустойСклад)
            И (ВЫБОР
                КОГДА СписанныеТовары.ДопустимыйСтатус1 <> &ПустойСтатус
                        ИЛИ СписанныеТовары.ДопустимыйСтатус2 <> &ПустойСтатус
                        ИЛИ СписанныеТовары.ДопустимыйСтатус3 <> &ПустойСтатус
                        ИЛИ СписанныеТовары.ДопустимыйСтатус4 <> &ПустойСтатус
                    ТОГДА ПартииТоваровНаСкладах.СтатусПартии = &ПустойСтатус
                            ИЛИ ПартииТоваровНаСкладах.СтатусПартии = &СтатусПартииПоОрдеру
                            ИЛИ ПартииТоваровНаСкладах.СтатусПартии = СписанныеТовары.ДопустимыйСтатус1
                            ИЛИ ПартииТоваровНаСкладах.СтатусПартии = СписанныеТовары.ДопустимыйСтатус2
                            ИЛИ ПартииТоваровНаСкладах.СтатусПартии = СписанныеТовары.ДопустимыйСтатус3
                            ИЛИ ПартииТоваровНаСкладах.СтатусПартии = СписанныеТовары.ДопустимыйСтатус4
                ИНАЧЕ ИСТИНА
            КОНЕЦ)
    
        И (ВЫБОР
            КОГДА СписанныеТовары.СписыватьТолькоПоЗаказу = ИСТИНА
                ТОГДА ВЫБОР
                        КОГДА ПартииТоваровНаСкладах.Заказ <> СписанныеТовары.ЗаказПартии
                            ТОГДА ВЫБОР
                                    КОГДА (НЕ СписанныеТовары.ЗаказПартии = НЕОПРЕДЕЛЕНО)
                                        ТОГДА ЛОЖЬ
                                    ИНАЧЕ ПартииТоваровНаСкладах.Заказ = &ПустойЗаказ
                                КОНЕЦ
                        ИНАЧЕ ИСТИНА
                    КОНЕЦ
            ИНАЧЕ ВЫБОР
                    КОГДА ПартииТоваровНаСкладах.Заказ <> СписанныеТовары.ЗаказПартии
                        ТОГДА ПартииТоваровНаСкладах.Заказ = &ПустойЗаказ
                    ИНАЧЕ ИСТИНА
                КОНЕЦ
        КОНЕЦ)
        И (СписанныеТовары.СерияНоменклатуры = ПартииТоваровНаСкладах.СерияНоменклатуры
            ИЛИ ПартииТоваровНаСкладах.СерияНоменклатуры = &ПустаяСерияНоменклатуры
ИЛИ СписанныеТовары.КодОперацииПартииТоваров = &КодРезервирование)
ГДЕ
    СписанныеТовары.Регистратор = &ОсновнойДокумент

УПОРЯДОЧИТЬ ПО
    ЧислоСерияНоменклатуры,
    ЧислоДокументОприходования,
    ЧислоЗаказ,
    ЧислоСтатусПартии,
    
    ДокументОприходования,
    ПартииТоваровНаСкладах.Склад
ИТОГИ ПО
    НомерСтрокиДокумента
;

///////////////////////////////////////////////////////////////////////////////
УНИЧТОЖИТЬ ПартииТоваровНаСкладах
8 NcSteel
 
14.10.15
10:02
(7) В УПП есть управляемые блокировки, куда ты собрался их вставить? 0_о
9 Sun_Storm
 
14.10.15
10:04
Его план получается вот такой (не знаю, как тут отформатируется):

Rows         Executes     StmtText                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      StmtId       NodeId       Parent       PhysicalOp           LogicalOp            Argument                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                             DefinedValues                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                               EstimateRows EstimateIO   EstimateCPU  AvgRowSize   TotalSubtreeCost OutputList                                                                                                                                                                                                                                                                                                                                                                  Warnings     Type         Parallel     EstimateExecutions
----         --------     --------                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      ------       ------       ------       ----------           ---------            --------                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                             -------------                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                               ------------ ----------   -----------  ----------   ---------------- ----------                                                                                                                                                                                                                                                                                                                                                                  --------     ----         --------     ------------------
1            1            Table Insert(OBJECT:([tempdb].[dbo].[#tt1]), OBJECT:([tempdb].[dbo].[#tt1]), SET:([tempdb].[dbo].[#tt1].[_Q_000_F_000RRef] = [Union1035],[tempdb].[dbo].[#tt1].[_Q_000_F_001_TYPE] = [Union1038],[tempdb].[dbo].[#tt1].[_Q_000_F_001_RTRef] = [Union1039],[tempdb].[dbo].[#tt1].[_Q_000_F_001_RRRef] = [Union1040],[tempdb].[dbo].[#tt1].[_Q_000_F_002RRef] = [Union1034],[tempdb].[dbo].[#tt1].[_Q_000_F_003RRef] = [Union1036],[tempdb].[dbo].[#tt1].[_Q_000_F_004RRef] = [Union1037],[tempdb].[dbo].[#tt1].[_Q_000_F_005RRef] = [Union1043],[tempdb].[dbo].[#tt1].[_Q_000_F_006RRef] = [Union1042],[tempdb].[dbo].[#tt1].[_Q_000_F_007] = [Expr1048],[tempdb].[dbo].[#tt1].[_Q_000_F_008] = [Expr1049],[tempdb].[dbo].[#tt1].[_Q_000_F_009RRef] = [Union1041]))                                                                                                                                                                                            0            0                         Table Insert         Insert               OBJECT:([tempdb].[dbo].[#tt1]), OBJECT:([tempdb].[dbo].[#tt1]), SET:([tempdb].[dbo].[#tt1].[_Q_000_F_000RRef] = [Union1035],[tempdb].[dbo].[#tt1].[_Q_000_F_001_TYPE] = [Union1038],[tempdb].[dbo].[#tt1].[_Q_000_F_001_RTRef] = [Union1039],[tempdb].[dbo].[#tt1].[_Q_000_F_001_RRRef] = [Union1040],[tempdb].[dbo].[#tt1].[_Q_000_F_002RRef] = [Union1034],[tempdb].[dbo].[#tt1].[_Q_000_F_003RRef] = [Union1036],[tempdb].[dbo].[#tt1].[_Q_000_F_004RRef] = [Union1037],[tempdb].[dbo].[#tt1].[_Q_000_F_005RRef] = [Union1043],[tempdb].[dbo].[#tt1].[_Q_000_F_006RRef] = [Union1042],[tempdb].[dbo].[#tt1].[_Q_000_F_007] = [Expr1048],[tempdb].[dbo].[#tt1].[_Q_000_F_008] = [Expr1049],[tempdb].[dbo].[#tt1].[_Q_000_F_009RRef] = [Union1041])                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                             2.66277      0.02         5.32554E-006 9            1.41913                                                                                                                                                                                                                                                                                                                                                                                                   PLAN_ROW     0            1                  
0            0              |--Compute Scalar(DEFINE:([Expr1048]=CONVERT_IMPLICIT(numeric(33,3),[Expr1047],0), [Expr1049]=CONVERT_IMPLICIT(numeric(33,2),[Expr1046],0)))                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                0            1            0            Compute Scalar       Compute Scalar       DEFINE:([Expr1048]=CONVERT_IMPLICIT(numeric(33,3),[Expr1047],0), [Expr1049]=CONVERT_IMPLICIT(numeric(33,2),[Expr1046],0))                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                            [Expr1048]=CONVERT_IMPLICIT(numeric(33,3),[Expr1047],0), [Expr1049]=CONVERT_IMPLICIT(numeric(33,2),[Expr1046],0)                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      &n
10 NcSteel
 
14.10.15
10:04
(8) + Так же естественно при проверке остатков и записи может блокироваться большой диапозон запией который приводит к эскалации.

Так что лучшим решением это отложенное проведение по партиям.
11 NcSteel
 
14.10.15
10:05
(9) не от (7) запроса.
12 Sun_Storm
 
14.10.15
10:07
(11) Да, точно, это после улучшения...
13 Sun_Storm
 
14.10.15
10:09
Старый я что-то не сохранил, это при помещении во временную таблицу партии товаров на складах, там из-за условия по ИЛИ план возвращает 56000 записей для физ таблицы партий.
14 Sun_Storm
 
14.10.15
10:10
(13) ну не сам план в конце, а промежуточно
15 NcSteel
 
14.10.15
10:12
вот тебе и ответ 56000 строк.
16 Sun_Storm
 
14.10.15
10:12
(8) Блокировки-то есть, но вот только перед удалением движений никаких блокировок не ставится, а сам факт удаления движений порождает Х-блокировку СУБД. по небольшому набору. А потом при проверке остатков из-за запроса ещё проставляется S-блокировка на больший диапазон.
17 NcSteel
 
14.10.15
10:13
Повторюсь, уже давно определились что надо делать, но ты упорный, толку только ноль.
18 NcSteel
 
14.10.15
10:13
(16) Все правильно, а говоришь что блокировок нет.
19 Sun_Storm
 
14.10.15
10:15
(18) Ну так в том месте где нужно, управляемых блокировок нет. А я сказал только о блокировках СУБД. После исправления запроса риск взаимоблокировки все равно останется.
20 NcSteel
 
14.10.15
10:16
(19) Блокировки есть, так где они нужны они установлены. При записи набора явно прописывать блокировки не нужно.

Еще раз, тебя не смущает эскалация?
Так что решение тут дано не раз
21 Sun_Storm
 
14.10.15
10:19
(17) Эскалация? Конечно я её исправлю. Я просто говорю, что взаимоблокировки все равно будут. Гораздо реже (может даже не встретятся), но будут.
22 Sun_Storm
 
14.10.15
10:19
(21) к (19)
23 Sun_Storm
 
14.10.15
10:19
точнее к (20)
24 Sun_Storm
 
14.10.15
10:20
Решение у меня есть. Я просто отписываюсь, в чем в итоге была проблема и как её буду исправлять.
25 Sun_Storm
 
14.10.15
10:29
(20) Почему ты считаешь, что при записи набора не надо прописывать блокировки? Ведь при контроле остатков, даже если убрать эскалацию, все равно будет блокироваться больший диапазон, чем блокируется при удалении движений? По крайней мере у меня после того, как я убрал условие по ИЛИ в параметрах вирт таблицы (ну ещё вынес подзапросы во временные на всякий случай) все равно выбиралось около 400 записей в процессе работы плана запроса.
26 Гёдза
 
14.10.15
10:33
(25) при записи блокировки устанавливаются АВТОМАТИЧЕСКИ
27 Гёдза
 
14.10.15
10:34
Опять же если включено разделение итогов, то такой блокировки НЕ ДОСТАТОЧНО
28 Sun_Storm
 
14.10.15
10:57
(25) Возможно, действительно, после исправления запроса будут выбираться только записи по набору измерений в наборе и тогда останется только поставить флаг БлокироватьДляИзменения при записи набора (разделение включено) и не ставить управляемые блокировки. Надо смотреть...
29 Sun_Storm
 
14.10.15
11:20
(26) Только этого может быть недостаточно.
Например, если мы в проведенном документе добавили строку, а потом нажали перепровести, то у нас:
Удаляются движения - блокировка набора без новой строки.
Запрос остатка - Блокировка всех записей с новой строкой.
Результат предсказуем.
30 NcSteel
 
14.10.15
15:20
(29) И какой результат? )))
31 Sun_Storm
 
14.10.15
17:23
(30) Пока результат такой - после оптимизации запроса взаимоблокировки остались. После детального изучения выяснилось, что 56000 строк после выполнения Clustered index seek - это если не использовать индекс ни по складу, ни по номенклатуре. После оптимизации запроса - 400 строк это без использования индекса по номенклатуре. Посмотрел, какие там вообще индексы есть. Оказалось, по номенклатуре вообще индекса нет. Номенклатура стоит первым измерением, но для регистров накопления это не важно. Снял замок с номенклатуры и проиндексировал.

Сейчас протестировал - взаимоблокировок не тех документах, на которых раньше были сейчас нет.

Это с учетом нового запроса и прописанных мною блокировок.

Завтра уберу управляемые блокировки, оставлю только флаг БлокироватьДляИзменения на будущее и снова протестирую.