Есть конфигурация:
Режим управления блокировкой данных в транзакции по умолчанию: Управляемый
Режим совместимости: Версия 8.3.8
Платформа: 1С:Предприятие 8.3 (8.3.10.2466)
Режим: Серверный (сжатие: усиленное)
Приложение: Тонкий клиент

Написал обработку для удаления документа "ЭлектронноеПисьмоВходящее"
Режим управления блокировкой данных в транзакции по умолчанию: Управляемый

Обработка может удалять документы в потоке, через фоновое задание.
Но если запустить больше 1 фонового задания, то вылетают ошибки:
Конфликт блокировок при выполнении транзакции:
Неустранимый конфликт блокировок

{ВнешняяОбработка.РегламентноеУдалениеВходящихЭлектронныхПисем.МодульОбъекта(214)}: Ошибка при вызове метода контекста (Удалить)
    СправочникОбъект.Удалить();
по причине:
Конфликт блокировок при выполнении транзакции:
Неустранимый конфликт блокировок
Или же
Конфликт блокировок при выполнении транзакции:
Неустранимый конфликт блокировок

{ВнешняяОбработка.РегламентноеУдалениеВходящихЭлектронныхПисем.МодульОбъекта(133)}: Ошибка при вызове метода контекста (Удалить)
     ДокументОбъект.Удалить();
по причине:
Конфликт блокировок при выполнении транзакции:
Неустранимый конфликт блокировок
Понятно что дело в наложении блокировок при удалении объектов.

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

Простой вариант не сработал:

```1c
    ДокументОбъект.Заблокировать()
```

Как переделать пример из справки для документ пока не понял:

```1c
    Блокировка = Новый БлокировкаДанных;
    ЭлементБлокировки = Блокировка.Добавить("РегистрНакопления.ТоварыНаСкладах");
    ЭлементБлокировки.УстановитьЗначение("Качество", Справочники.Качество.НайтиПоКоду("1"));
    ЭлементБлокировки.Режим = РежимБлокировкиДанных.Исключительный;
    ЭлементБлокировки.ИсточникДанных = ДокументОбъект.ВозвратнаяТара;
    ЭлементБлокировки.ИспользоватьИзИсточникаДанных("Номенклатура", "Номенклатура");
    ЭлементБлокировки.ИспользоватьИзИсточникаДанных("Склад", "Склад");
    Блокировка.Заблокировать();
```

Есть идеи обхода? Так же конфликт блокировок возник этой ночью даже в 1 потоке, скорее всего загружалась почта регламентным заданием.
---
Как переделать пример из справки для документ пока не понял:

см. тут https://its.1c.ru/db/metod8dev#content:5839:hdoc

Для объектных данных (справочник, документ и др.) определено единственное пространство блокировки - сам объект данных.

По большому счету только так:

```1c
    Блокировка = Новый БлокировкаДанных;
    ЭлементБлокировки = Блокировка.Добавить("Документ.ЭлектронноеПисьмоВходящее");
    ЭлементБлокировки.Режим = РежимБлокировкиДанных.Исключительный;
    Блокировка.Заблокировать();
```

Но только ни о какой многопоточности в этом случае можете не мечтать. Т.к. после запуска первого фонового задания оно заблокирует всю таблицу документов и второе все последующие фоновые задания будут ожидать пока завершится первое фоновое задание и освободят таблицу с документами.
---
За 5 минут работы 10 потоков пока ни одной отмены транзакции:

```1c
    Попытка
    НачатьТранзакцию(РежимУправленияБлокировкойДанных.Управляемый);
    Блокировка = Новый БлокировкаДанных;
    ЭлементБлокировки = Блокировка.Добавить("Документ.ЭлектронноеПисьмоВходящее");
    ЭлементБлокировки.Режим = РежимБлокировкиДанных.Исключительный;
    ЭлементБлокировки.УстановитьЗначение("Ссылка", ТекущиеДанные.Данные.Ссылка);
    Блокировка.Заблокировать();

    ДокументОбъект.Удалить();

    ЗафиксироватьТранзакцию();
    Исключение
    ОтменитьТранзакцию();
    КонецПопытки;
```

Отпишу в конце дня как отработали 3 потока за день.
---
изучил данные транзитивного замыкания и понял что они мне ничем не помогут. Написал простой запрос, где документ основание не заполнен и получил свои вершки! И все с пересечениями покончено!
---
Перед удалением в каждом потоке проверяйте на доступность объекта для удаления.
---
под "доступность" речь идет о методе
```1c
    Заблокирован
```

(11) возможно это решение. Надо будет проверить.
---
Да, и еще существует удаляемый объект или нет
---
Ну и как вариант, использовать общую выборку документов для всех потоков, и синхронизировать список, что бы потоки не выбирали один и тот же документ для удаления
---
Не совсем понял, как блокировки помогут в борьбе с блокировками :)
Хочешь просто уменьшить таймаут при конфликтах?
Если будешь через Заблокирован() пытаться решить - внимательно читай справку. Он между сессиями не работает. Там надо именно блокировать в попытке/исключении и если эксепшн - значит заблокирован в другой сессии.
Но мне вообще не совсем понятно, как ты делаешь. Какую используешь стратегию при наличии связанных писем? Прибивать всю цепочку вверх и вниз?
А по дефолту воркерам раздаешь диапазоны дат? Как-то оно с цепочками все неочевидно... Надо/не надо, если надо, то до каких пор...
---
стратегию связанных писем не делал. Думаю над этим из совета (11) .

(14) не понял о чем речь можно разжевать?
---
Когда 1 из потоков удаляет объект у других потоков этот объект находится в списке для удаления, нужно это проверить, если кончено вы не используете общий список для потоков.
---
именно так и происходит Когда 1 из потоков удаляет объект у других потоков этот объект находится в списке для удаления
Писал про это в (7)
---
Как переделать пример из справки для документ пока не понял:

см. тут https://its.1c.ru/db/metod8dev#content:5839:hdoc

Для объектных данных (справочник, документ и др.) определено единственное пространство блокировки - сам объект данных.

По большому счету только так:

```1c
    Блокировка = Новый БлокировкаДанных;
    ЭлементБлокировки = Блокировка.Добавить("Документ.ЭлектронноеПисьмоВходящее");
    ЭлементБлокировки.Режим = РежимБлокировкиДанных.Исключительный;
    Блокировка.Заблокировать();
```

Но только ни о какой многопоточности в этом случае можете не мечтать. Т.к. после запуска первого фонового задания оно заблокирует всю таблицу документов и второе все последующие фоновые задания будут ожидать пока завершится первое фоновое задание и освободят таблицу с документами.
---
спасибо за совет проверю и этот вариант.
А почему именно исключительный нужно ставить?
---
А почему именно исключительный нужно ставить?

Разделяемая блокировка устанавливается для того, чтобы данные не были изменены другими транзакциями. Исключительная блокировка, помимо этого, обеспечивает запрет не только изменения этих данных, но даже их чтения другими транзакциями, устанавливающими управляемые блокировки. Можно сказать, что исключительная управляемая блокировка является средством борьбы с конфликтами блокировок (deadlock) и может использоваться аналогично ключевому слову ДЛЯ ИЗМЕНЕНИЯ языка запросов в режиме автоматических блокировок.

судя по ошибке

Неустранимый конфликт блокировок

у вас как раз Дедлок
---
Режим: Серверный (сжатие: усиленное)

MSSQL?
---
да.
---
Вот как раз это не решит проблему в принципе (на сколько я понял проблему).
Похоже блокировка как раз и накладывается при получении объекта документа. И на все реквизиты, в которых есть ВзаимодействиеОснование, где и хранится ссылка на другой документ Письмо. На документ основание также накладывается блокировка. И тут кто первый захватил объект. Будет конфликт блокировок. Можно конечно попробовать установить разделяемую блокировку, но не уверен, что поможет. Это все при условии, что в разных потоках обрабатываются разные документы.
Возможно в данном случае самым простым будет удалять документы средствами самого sql. Или все делать одним потоком частями.

ps. И для удаления в потоках ведь используется транзакция? И пока транзакция не завершена, все захваченные документы заблокированы...
---
Удаление происходит получением Объекта Документ и последующим его удалением?
Может стоит использовать метод глобального контекста УдалитьОбъекты? С проверкой ссылочной целостностью.
---
Удаление происходит получением Объекта Документ и последующим его удалением да так и делаю проверку ссылочной целости через поиск ссылок делал.
Возможно это решение. Но надо проверить на практике.
---
да так и делаю проверку ссылочной целости через поиск ссылок делал.
я не совсем про это.
УдалитьОбъекты(<СписокСсылок>, <Проверять>, <НайденныеДанные>, <ОбластьПоиска>, <ВключитьОбъекты>, <ИсключитьОбъекты>)
Вот второй параметр установить в ИСТИНА. Т.е. тут уже встроенная проверка есть.
---
наверное для меня УдалитьОбъекты не подойдет. Т.к. мне надо удалять только по условию:

```1c
    Если Не ТекущиеДанные.Данные.Важность = ПредопределенноеЗначение("Перечисление.ВариантыВажностиВзаимодействия.Высокая") Тогда
```

Поэтому сделал ход конем:

```1c
    Если ТаблицаСсылок.Количество() = 0 Тогда
    Попытка
    ДокументОбъект.Удалить();
    Исключение
    ДокументОбъект.УстановитьПометкуУдаления(Истина);
    КонецПопытки;
    Иначе
    ДокументОбъект.УстановитьПометкуУдаления(Истина);
    КонецЕсли;
```

Или же

```1c
    Если ТаблицаСсылок.Количество() = 0 Тогда
    Попытка
    СправочникОбъект.Удалить();
    Исключение
    СправочникОбъект.УстановитьПометкуУдаления(Истина);
    КонецПопытки;
    Иначе
    Для Каждого ТекущиеДанныеСсылки Из ТаблицаСсылок Цикл
    Сообщить(" " + СокрЛП(ТекущиеДанныеСсылки[0]) + " " + СокрЛП(ТекущиеДанныеСсылки[1]));
    КонецЦикла;
    КонецЕсли;
```

Как я понял запуская несколько потоков получается пересечение:
Первый поток:
Документ1 (Справочник11; Регистр11; Регистр12) -> Документ2 (Справочник21; Регистр21; Регистр22) -> Документ3 (Справочник31; Регистр31; Регистр32)
Цепочка в потоке 1 сформировалась методом "НайтиПоСсылкам".
Второй поток:
Документ3 (Справочник31; Регистр31; Регистр32) -> Документ4 (Справочник41; Регистр41; Регистр42)

В итоге когда происходит наложения обращения потоков к одним и тем элементам БД. Происходит конфликт блокировок.
Попытка решила проблему. Т.к. поток который хочет удалить объект по логике не должен этого делать. За него это сделает поток, который пришел выше по цепочке.
Итог:
Остается проверить останутся ли не удаленные письма после отработки фоновых заданий.

На 4 ядерном сервере 4 потока жрут 96-100% ЦП. Т.к. по выходным там еще и пользователи могут работать больше потоков не думаю что стоит на нем ставить.
Думаю такое решение решает мою проблему на корню!
---
Как вариант, сделайте удаление в транзакции с исключительной блокировкой удаляемой ссылки, тогда все дочерние удаляемые объекты тоже должны удалятся с исключительной блокировкой, например:
Попытка
НачатьТранзакцию(РежимУправленияБлокировкойДанных.Управляемый);
Далее блокировка удаляемого объекта и удаление

ЗафиксироватьТранзакцию();

Исключение
  ОтменитьТранзакцию();
КонецПопытки;
---
наверное для меня УдалитьОбъекты не подойдет. Т.к. мне надо удалять только по условию
Кто мешает подготовить список нужных ссылок?
---
А вы не думаете, что проблема в эскалации?
Я писал примерно тоже самое, причем документы были независимы. Ошибка была примерно такая же. И проблема была именно в эскалации.

Может быть вам стоит попробовать по-другому формировать данные для удаления. Т.е. сначала удалить письма без ссылок и удалять все зависимые элементы.
---
т.е. сначала в потоках удалить все документы, которые не имеют зависимых ссылок на такие же документы, а затем один потокам удалять документы с зависимостями?
---
Сначала лучше посмотреть, действительно ли эскалация имеет место.
Настраиваете профайлер и проверяете наличия событий SQL Server Profiler Lock:Escalation.

Да, как-то так.
Т.е. есть цепочка:
Документ1 -> Документ2 -> Документ3

Сначала удаляем Документ3 + связь (если она отдельная) и т.д.
Я такое проделывал на Документообороте, там связи отдельно хранятся.
---
Escalation это где смотреть?
Сначала вывел все события лог прикрепил, затем оставил только эскалацию скрин прикрепил.
9 из 10 фоновых заданий напоролись на блокировку, а лог пустой! Значит не эскалация это?
---
Значит не эскалация.
Как вариант еще можно ТЖ на ошибки настроить, там и объектные блокировки отобразятся.
---
так я и так знаю что есть блокировки.
Как их обходить?

Вот смотри есть документ1 -> документ2 -> документ3.
Я в потоке 1 начал обходить все зависимые ссылки документ1, а во втором потоке документ3. Наверное когда второй поток удаляет документ3 он натыкается на блокировку первого потока?
---
Да, но блокировки могут быть объектные, а могут быть и нет.
Поэтому сначала нужно отобрать все Документ3, а потом подниматься на уровень выше.
Или еще вариант выделять какое-то временное хранилище, куда складывать документы, которые сейчас удаляются.
Либо удалять без проверки ссылочной целостности, а потом просто заменить битые ссылки пустыми ТИИ.
---
А зачем все удалять?
TRUNCATE TABLE =)))
---
ну транк я делал на копии, чтобы обновление быстрее прошло. А в рабочей часть инфы надо оставить!

(8) пока не понял как мне запросом это сделать! Ведь в документ3 нет ссылок на вышестоящие. Понять что он последний в цепочке пока могу только найдя все ссылки, но это же постфактум, когда потоки уже поделены!
---
Понять что он последний в цепочке пока могу только найдя все ссылки, но это же постфактум, когда потоки уже поделены!

Запросом находим, все документы которые ссылаются на другие документы, а потом НЕ В (ВЫБРАТЬ * ИЗ ВсеДокументыСоСсылками).

Второй вариант сливаем нужные данные в файл (выгрузка загрузка XML/JSON), TRUNCATE, а потом заливаем обратно
---
Я бы делал примерно так, чтобы не заморачиваться с очередями:
1) раздал потокам диапазоны дат и общую верхнюю границу, по которую очищается ящик в принципе
2) в каждом потоке для каждого удаляемого письма определяется вся цепочка, в которой оно участвует и если последнее письмо раньше общей верхней границы удаления - то письма цепочки не удаляются (при этом не забыть удалить все письма цепочки из общего пула писем, которые должен удалить конкретный поток, чтобы не делать дурную работу несколько раз).
3) если же последнее письмо цепочки позже общей границы чистки ящика, но цепочка выходит за пределы дат конкретного потока, тогда пытаться его заблокировать (через Заблокировать(), а не через управляемую блокировку). Если ексепшн - значит пропускаем, т.к. цепочку уже удаляет другой поток (цепочку удаляем с конца). Если вся цепочка в пределах дат удаления потока - тогда просто удаляем, без блокировок.
4) после завершения всех потоков из главного потока запускаем контрольный поток, который должен почистить хвосты. Хвостов при такой схеме быть не должно. Если будут - попытаться разобраться в причинах.
---
вот вопрос как проще реализовать пункт 2.
---
что мешает сделать так?
1. Выбрать весь перечень документов для удаления одним запросом.
2. Поместить все в массив (ТЗ, СписокЗначений - не важно).
3. Действовать по алгоритму:

а. Определяем количество потоков.
б. Запускаем цикл по перебору списка документов.
в. проверяем не превышено ли число запущенных потоков, если нет
г. В теле цикла получаем документ для удаления и убираем его из общего списка документов (из массива)
д. Запускаем новое фоновое задание на удаление объекта
ж. если лимит потоков достигнуд ждем завершения любого фонового задания.
з. фоновое задание завершено GoTo пункт Г.
---
Ответ давно известен. Серией запросов вида Родитель, Родитель.Родитель, Родитель.Родитель.Родитель.
Т.е. в одном запросе получаешь, скажем, пять родителей. Если это еще не все - фигачить запрос на следующие пять.
Можно в идеале заморочиться определением всех цепочек перед раздачей заданий. И выдавать заданиям непересекающиеся пулы сообщений для удаления.
Но, боюсь, тогда узким местом может стать главный поток.
---
Вероятно у вас управляемые блокировки, а таймаут возникает в СУБД.
Блокировка ссылки вообще тут не при чем.
При удалении СУБД накладывает блокировку не на ссылку, а на диапазон. Гуру скажут точнее... Эскалация на объектных данных возможна, но маловероятна.
И давайте вспомним что ещё удаляется при удалении объектов??? Регистры сведений с ведущими измерениями!!! В тж или ещё где-то вы не увидите. Только в трассировке скл. Вот там-то широченные диапазоны или эскалации гарантированы.
---
как уже было сказано эскалацией нет.

(35) так зачем, если попытка решает вопрос? И в топике я про блокировки же писал. Этот код что-то меняет?

(36) в том что объектов более 2 лямов. А удаляю я только те что соответствуют условию и в заданном периоде, плюс раскидать по потокам нужно!
Список нужных я и так получаю для раскидывания по потокам. Поэтому не совсем понимаю о каком списке идет речь.

Запустил на ночь 10 потоков проц 100% загружен. Посмотрим что на утром будет!
---
как уже было сказано эскалацией нет.
Есть таймауты на блокировке. Эскалация - это не первопричина блокировки. Первопричина - пересечение пространств, в первую очередь таблицах, во вторую - на диапазонах ключей документов или регистров сведений. Эскалация как таковая при удалении малоинтересна.

(1) ради увеличения знаний и опыта данная задача хороша, но на практике такую реализацию лучше не применять.
Вы до упора пытаетесь нагрузить железо... положить проц или диски для чего? Если не успеете за ночь удалить документы, то следующей ночью это сделать нельзя? Почему нельзя регламентно их вычищать каждую ночь, без фанатизма... ?

АП: ой, сорри!!!! разул глаза и прочитал сабж ))) У вас же ошибка: дедлок ) Это же меняет дело.
Проще забить и выполнять в попытке.
---
Вы до упора пытаетесь нагрузить железо... положить проц или диски для чего?
У меня похожая проблема, ни на проц, ни на диски нагрузки фактически ни какой, хотя объем удаляемой информации в общей сложности достигает 10млн строк. Фоновые задания со временем уходят в ступор, даже делал без фоновых заданий, запускал несколько 1С с обработкой, со временем одна за одной копии зависали намертво, рабочей оставалась только одна. Проблемы с взаимоблокировками попадаются очень редко, 1-2 раз на неделю работы обработки.
---
значит я правильно сделал в (33). И правильно понял суть этих блокировок?

(39) я хотел узнать стоит ли вообще их использовать, мой код не использует блокировок.
---
И правильно понял суть этих блокировок?
Режим блокировок зависит от настроек конфигурации и скл сервера, в вашем коде вы не устраните взаимоблокировки, другой поток все равно будет читать тот же объект, за счет режима "грязного чтения" в скл сервере. Необходимо принудительно блокировать удаляемый объкет для исключительного доступа, например:
.....
.....
ЭлементБлокировки.Режим = РежимБлокировкиДанных.Исключительный;
ЭлементБлокировки.УстановитьЗначение("Ссылка", ДанныеКУдалению.Данные);
Блокировка.Заблокировать();

Но перед этим открывать транзакцию, описывал выше.
---
За 11 часов работы 2 потока отвалились на пометке удаления из-за не соответствия версий.

(42) попробую написать удаление через транзакцию с блокировкой, но без попытки
(43) предполагать не нужно посмотрите мою запись по (33) посту алгоритм наложения потоков я там описал!
---
предполагать не нужно посмотрите мою запись по (33) посту алгоритм наложения потоков я там описал!
В посте вы сделали совершенно неверные выводы.
1. Похоже вы так и не поняли про какие РС говорил я
2. совершенно не понятно из темы какие регистры очищаете вы. Какое отношение они имеют к документам? Это движения? Потому что речь шла только о документах.
3. С какого перепугу у вас два потока удаляют один и тот же объект?? Вы что в каждом потоке выполняете отдельно найти по ссылкам?? Каждый поток должен обрабатывать свою часть порцию из общего. Конфликта блокировок при конфликте версий не будет. У них разные причины.
Т.е. прочитали свои два миллиона доков. Порциями по 10000 запускаете нужное количество фоновых. Пересечения никогда нет.
---
проверяю как будет такой код работать:

```1c
    НачатьТранзакцию(РежимУправленияБлокировкойДанных.Управляемый);
    Блокировка = Новый БлокировкаДанных;
    ЭлементБлокировки = Блокировка.Добавить("Документ.ЭлектронноеПисьмоВходящее");
    ЭлементБлокировки.Режим = РежимБлокировкиДанных.Исключительный;
    ЭлементБлокировки.УстановитьЗначение("Ссылка", ТекущиеДанные.Данные.Ссылка);
    Блокировка.Заблокировать();
    ЗафиксироватьТранзакцию();
```
---
ожидаемо. Из выборки 6000+ документов осталось живыми 89. Очевидно это те самые пересечения.
(52) 1. Не понял. 2-3. Удаляю я входящие письма. В CRM на них вешается куча регистров сведений независимых. Я делаю выборку нужных документов. Далее поиском ссылок убиваю все ссылки. Периодически попадаются ссылки на вышестоящие входящие письма. Я же поделил потоки поровну, а не согласно иерархии, которую не так то просто построить, если только циклы не городить.
---
Из выборки 6000+ документов осталось живыми 89. Очевидно это те самые пересечения.
В такой ситуации лучшим вариантом будет усыпление потока с дальнейшим повторением удаления и установкой порога попыток( что бы не зашел в цикл)
---
что значит усыпление?
---
Сорри. В 1С нет такого понятия, просто запустите цикл с привязкой по времени, время рассчитайте исходя из частоты ваши процессоров на сервере 1С, например
Конец = ТекущееВремя() + 5000;
Пока Конец > ТекущееВремя() Цикл КонецЦикла;
---
я думаю тогда можно заносить в повторный массив такие ссылки и после окончания основного цикла выполнить повторно не удаленные. А такой цикл мне кажется все равно не корректный, иногда и по 10 секунд 1 документ удаляется.

Хотя можно ничего не делать. А потом повторить удаление с новой выборкой.
---
Вполне нормальный цикл, вам просто нужна задержка, для того что бы другие потоки могли выполнить код удаления, совпадение времени в разных потоков маловероятно. Но я пошел в своей обработке по медленному пути:
 делал таблицу ссылок со счетчиком попыток с сортировкой так что бы признак попытка находился внизу или вверху списка в зависимости от алгоритма выборки. Но можно и в отдельный массив выложить, это дело вкуса.
---
наконец стало понятно про какие вы регистры говорите.
ни в одном посте так конкретно и не сказано используете ли вы транзакции, Но судя по блокировкам - это так. Если да, то зачем?
Вы можете спокойно удалить сначала регистры, а потом документы.
Можете документы, а потом регистры с битым измерением.
Мне кажется вообще нет здесь никаких проблем.
---
я удаляю объект, только если нет на него ссылок! Таким образом я себе гарантирую, что все транзакции прошли.

Изначально транзакции я не использовал. В (46) я применил транзакции для ссылок. В (47) для регистров, но поняв что это бессмысленно, удалил для них.
Блокировок больше нет. Т.к. потоки не читают вложенные данные при явных блокировка. Но остается вопрос пропущенных объектов, который решается повторных проходом, таймаутом или запуском в 1 потоке остатка.
---
так зачем, если попытка решает вопрос?
Вам же полностью надо удалить объект, смысл ставить пометку.
Этот код что-то меняет?
Должен, без открытой транзакции установленные вами блокировки игнорируются, удаление происходит по стандартной схеме.
---
Если вы явно не используете транзакции, то происходит удаление объекта в неявной транзакции. Если предположить, что кроме объекта ничего не удаляется, то никаких дедлоков быть не должно в принципе. Для организации дедлока нужны как минимум по два объекта в конфликтующих транзакциях.
Если дедлоки встречаются, то причины ищите здесь: 1. происходит удаление наборов записей (например движения, или какой-нибудь РС.ВерсииОбъектов), 2. выполняются обработчики удаления объекта.

ЭлементБлокировки.УстановитьЗначение("Ссылка", ДанныеКУдалению.Данные);
Такой код избыточен, т.к. такая блокировка платформой накладывается сама.
Чтобы избежать дедлока нужно открывать транзакцию самому и блокировать все что будет писаться в базу в нагрузку к ссылке.
---
Такой код избыточен, т.к. такая блокировка платформой накладывается сама.
Блокировка накладывается в разделяемом режиме, что позволяет другим сессиям читать этот объект (грязное чтение)
---
я так и подумал. Убираю за ненадобностью. Тогда оставляю блокировки только на ссылочные типы данных. Меня такой результат более чем устраивает!
---
при удалении документа разделяемая блокировка на ссылку?
Неожиданно. Мы точно говорим про менеджер блокировок 1с, а не СУБД??? Откуда такая информация? Чем подтвердите?
---
Много вопросов, проверьте сами.
---
При записи любого объекта платформа сама неявно устанавливает исключительную управляемую блокировку на ссылку (для 8.3. еще и на поля блокировки)
Такие события не регистрируются в ТЖ, а на ИТС что не нашел информации (
Попробую смоделировать ситуацию...
---
Если бы это было так, то конфликта блокировок на уровне скл сервера не было бы, 1С при записи объекта блокирует только те таблицы sql в которые пишет, остальные могут изменить другие сессии, результат конфликт блокировок в глобальной транзакции изменения объекта. По нормальному, при записи должны заблокироваться все записи в таблицах связанных с объектом
---
1с никаких блокировок в СУБД не устанавливает.
Есть два вида конфликтов блокировок: ожидание (как следствие таймаут) и взаимоблокировка. Вы по какой говорите?
---
Блокировка неявно устанавливается скл сервером, когда 1с пишет в его таблицы данные.
взаимоблокировка - она чаще всего происходит, по ожиданию редко бывают, только если вы запустите транзакцию и будете в ней изменять кучу данных.
---
при правильном коде дедлоков быть не должно вообще. Если они есть - нужно их устранять.
Ожидания есть всегда. Вообще всегда, при параллельной работе. Если доходит до таймаута - нужно оптимизировать.
Т.е. дедлоки - это ошибка программиста. Таймаут - это неоптимальность.
Неявные блокировки устанавливает и 1с и скл.
Я говорил именно про неявную в 1с, т.к. ошибка не скульная, 1с-ная.
---
Даже при правильном кодинге в 1С, дедлоков не избежать, пока на уровне платформы 1С нормально не реализуют объектную базу 1С, на уровне реляционной базы sql
---
чушь.
Сможете выстроить схему дедлоков при "правильном коде"? Или я ее тоже сам должен придумать?)
Годами работают проекты по 200-500 весьма активных пользователей без единого дедлока после оптимизации и исправления.
---
Это ваше мнение, играть в пинг понг я с вами не собираюсь. Что такое 200-500 интерактивных пользователей, это даже меньше чем конкретный пример с 10 активными потоками, с нагрузкой на несколько таблиц скуля.
---
(70+ Я вам уже выше описал схему блокировок при изменении объекта в базе скуля.
---
+ А когда мы блокируем вручную ссылку, остальные сессии просто не могут прочитать эту ссылку и соответственно связанные записи в других таблицах объекта не читаются.
---
За 5 минут работы 10 потоков пока ни одной отмены транзакции:

```1c
    Попытка
    НачатьТранзакцию(РежимУправленияБлокировкойДанных.Управляемый);
    Блокировка = Новый БлокировкаДанных;
    ЭлементБлокировки = Блокировка.Добавить("Документ.ЭлектронноеПисьмоВходящее");
    ЭлементБлокировки.Режим = РежимБлокировкиДанных.Исключительный;
    ЭлементБлокировки.УстановитьЗначение("Ссылка", ТекущиеДанные.Данные.Ссылка);
    Блокировка.Заблокировать();

    ДокументОбъект.Удалить();

    ЗафиксироватьТранзакцию();
    Исключение
    ОтменитьТранзакцию();
    КонецПопытки;
```

Отпишу в конце дня как отработали 3 потока за день.
---
хотя забыл же дописать удаление объектов.
Отмены транзакций пошли, но пока отследил только для регистров.
Для документа и справочника отмен транзакций нет.
Единственный нюанс такого подхода возможно, что часть объектов не удалится?

Отмены транзакций по регистрам пошли потому что похоже 2 потока удаляют одну и туже запись регистра? И тот кто первый успел ее удалить удаляет, а второй отменяет транзакцию?
И написав для них такую же блокировку я смогу убрать отмены транзакций и для регистров?
Хотя странно. Отмены транзакций идут по регистрам которые не имеют ссылок на удаляемые объекты.
Поискал и на удаляемые тоже нашел.

Удаление в регистре происходит:

```1c
    НаборЗаписей = РегистрыСведений[ИмяРегистра].СоздатьНаборЗаписей();
    НаборЗаписей.Отбор[ИмяОтбора].Установить(ТекущиеДанные.Ссылка);
    НаборЗаписей.Прочитать();
    НаборЗаписей.Очистить();
    НаборЗаписей.Записать();
```

Значит транзакцию писать нужно так:

```1c
    Попытка
    НачатьТранзакцию(РежимУправленияБлокировкойДанных.Управляемый);
    Блокировка = Новый БлокировкаДанных;
    ЭлементБлокировки = Блокировка.Добавить("РегистрСведений." + ИмяРегистра);
    ЭлементБлокировки.Режим = РежимБлокировкиДанных.Исключительный;
    ЭлементБлокировки.УстановитьЗначение(ИмяОтбора, ТекущиеДанные.Ссылка);
    Блокировка.Заблокировать();
    НаборЗаписей = РегистрыСведений[ИмяРегистра].СоздатьНаборЗаписей();
    НаборЗаписей.Отбор[ИмяОтбора].Установить(ТекущиеДанные.Ссылка);
    НаборЗаписей.Прочитать();
    НаборЗаписей.Очистить();
    НаборЗаписей.Записать();
    ЗафиксироватьТранзакцию();
    Исключение
    ОтменитьТранзакцию();
    КонецПопытки;
```
---
блокировка на регистры не возымела значения. В ЖР все равно появляются транзакции по отмене, или так и должно быть?
---
Блокировка на регистры идет по измерениям и (или) периоду, или по регистратору. Нужно устанавливать блокировку на все измерения. Если происходит исключение, то да возможен конфликт на регистре, отменить всю транзакцию с удалением документа, и пропишите алгоритм так что бы он повторил это действие через некоторое время с соответствующей проверкой на существование объекта или записей регистра. Удалять регистры лучше через менеджер записи (правда такое удаление медленнее), в таком режиме риск попасть на дедлок меньше.
---
Давно читал статью про транзитивное замыкание https://infostart.ru/public/158512/.
Думаю это будет оптимальное решение. Таким образом, сделав выборку верхнего уровня у меня не будет пересечений, если за время выполнения потоков не произойдет изменений структуре иерархий, что мало вероятно в ночное время!
---
Если только ограничится не большой областью данных
---
речь идет о скорости выполнения запроса? Обычно я беру выборку за месяц там около 100к записей.
---
А зачем выбирать все документы, достаточно в каждом потоке выбирать по 100-200 записей, удалять их, завершать работа и ждать следующего запуска.
---
тогда будут пересечения. Запрос должен быть общий для всех потоков. А получив выборку верхнего уровня раскидываем по потокам. Таким образом пересечений в потоках не будет!
---
Можно и так, я перед удалением контрольным запросом делаю выборку ссылки
---
9 секунд на 33к строк.
Текст запроса:

```1c
    ВЫБРАТЬ ВзаимодействиеОснование НачалоДуги, Ссылка КонецДуги ПОМЕСТИТЬ ЗамыканияДлины1 ИЗ Документ.ЭлектронноеПисьмоВходящее
    ГДЕ ВзаимодействиеОснование <> Значение(Документ.ЭлектронноеПисьмоВходящее.ПустаяСсылка)
    И Дата <= &ДатаУдаления
    И Важность <> Значение(Перечисление.ВариантыВажностиВзаимодействия.Высокая)
    ОБЪЕДИНИТЬ ВЫБРАТЬ Ссылка, Ссылка ИЗ Документ.ЭлектронноеПисьмоВходящее
    ГДЕ Дата <= &ДатаУдаления
    И Важность <> Значение(Перечисление.ВариантыВажностиВзаимодействия.Высокая);ВЫБРАТЬ РАЗЛИЧНЫЕ ПерваяДуга.НачалоДуги, ВтораяДуга.КонецДуги ПОМЕСТИТЬ ЗамыканияДлины2 ИЗ ЗамыканияДлины1 КАК ПерваяДуга
    ВНУТРЕННЕЕ СОЕДИНЕНИЕ ЗамыканияДлины1 КАК ВтораяДуга ПО ПерваяДуга.КонецДуги = ВтораяДуга.НачалоДуги;
    УНИЧТОЖИТЬ ЗамыканияДлины1;ВЫБРАТЬ РАЗЛИЧНЫЕ ПерваяДуга.НачалоДуги, ВтораяДуга.КонецДуги ПОМЕСТИТЬ ЗамыканияДлины4 ИЗ ЗамыканияДлины2 КАК ПерваяДуга
    ВНУТРЕННЕЕ СОЕДИНЕНИЕ ЗамыканияДлины2 КАК ВтораяДуга ПО ПерваяДуга.КонецДуги = ВтораяДуга.НачалоДуги;
    УНИЧТОЖИТЬ ЗамыканияДлины2;ВЫБРАТЬ РАЗЛИЧНЫЕ ПерваяДуга.НачалоДуги, ВтораяДуга.КонецДуги ПОМЕСТИТЬ ЗамыканияДлины8 ИЗ ЗамыканияДлины4 КАК ПерваяДуга
    ВНУТРЕННЕЕ СОЕДИНЕНИЕ ЗамыканияДлины4 КАК ВтораяДуга ПО ПерваяДуга.КонецДуги = ВтораяДуга.НачалоДуги;
    УНИЧТОЖИТЬ ЗамыканияДлины4;ВЫБРАТЬ РАЗЛИЧНЫЕ ПерваяДуга.НачалоДуги, ВтораяДуга.КонецДуги ПОМЕСТИТЬ ЗамыканияДлины16 ИЗ ЗамыканияДлины8 КАК ПерваяДуга
    ВНУТРЕННЕЕ СОЕДИНЕНИЕ ЗамыканияДлины8 КАК ВтораяДуга ПО ПерваяДуга.КонецДуги = ВтораяДуга.НачалоДуги;
    УНИЧТОЖИТЬ ЗамыканияДлины8;ВЫБРАТЬ РАЗЛИЧНЫЕ ПерваяДуга.НачалоДуги, ВтораяДуга.КонецДуги ПОМЕСТИТЬ ЗамыканияДлины32 ИЗ ЗамыканияДлины16 КАК ПерваяДуга
    ВНУТРЕННЕЕ СОЕДИНЕНИЕ ЗамыканияДлины16 КАК ВтораяДуга ПО ПерваяДуга.КонецДуги = ВтораяДуга.НачалоДуги;
    УНИЧТОЖИТЬ ЗамыканияДлины16;ВЫБРАТЬ РАЗЛИЧНЫЕ ПерваяДуга.НачалоДуги, ВтораяДуга.КонецДуги ПОМЕСТИТЬ ЗамыканияДлины64 ИЗ ЗамыканияДлины32 КАК ПерваяДуга
    ВНУТРЕННЕЕ СОЕДИНЕНИЕ ЗамыканияДлины32 КАК ВтораяДуга ПО ПерваяДуга.КонецДуги = ВтораяДуга.НачалоДуги;
    УНИЧТОЖИТЬ ЗамыканияДлины32;ВЫБРАТЬ РАЗЛИЧНЫЕ ПерваяДуга.НачалоДуги, ВтораяДуга.КонецДуги ПОМЕСТИТЬ ЗамыканияДлины128 ИЗ ЗамыканияДлины64 КАК ПерваяДуга
    ВНУТРЕННЕЕ СОЕДИНЕНИЕ ЗамыканияДлины64 КАК ВтораяДуга ПО ПерваяДуга.КонецДуги = ВтораяДуга.НачалоДуги;
    УНИЧТОЖИТЬ ЗамыканияДлины64;ВЫБРАТЬ РАЗЛИЧНЫЕ ПерваяДуга.НачалоДуги, ВтораяДуга.КонецДуги ПОМЕСТИТЬ ЗамыканияДлины256 ИЗ ЗамыканияДлины128 КАК ПерваяДуга
    ВНУТРЕННЕЕ СОЕДИНЕНИЕ ЗамыканияДлины128 КАК ВтораяДуга ПО ПерваяДуга.КонецДуги = ВтораяДуга.НачалоДуги;
    УНИЧТОЖИТЬ ЗамыканияДлины128;ВЫБРАТЬ НачалоДуги Предок, КонецДуги Потомок ИЗ ЗамыканияДлины256 ГДЕ НачалоДуги <> КонецДуги
```

Как теперь получить дерево?
---
Дерево будет медленно работать, лучше в таблице сортировать
---
изучил данные транзитивного замыкания и понял что они мне ничем не помогут. Написал простой запрос, где документ основание не заполнен и получил свои вершки! И все с пересечениями покончено!
---
Ну это хорошо, а у меня так и не получается решить проблему с висяками, подозреваю что это проблема в платформе. Правда у меня идет сканирование всей базы, где в некоторых таблицах больше миллиона записей
---
Я думаю, что автор слишком все усложняет. Все можно сделать куда проще - просто добавить заглушку в объекте при удалении, чтобы объект не пытался удалять подчиненные объекты и проверять наличие родителей. В итоге код сведется к простому удалению объектов в несколько потоков.
---
для этого мне нужно построить дерево или получить только верхние строки дерева, полученного из запроса (79).
---
для этого мне нужно построить деревоЕсли Вы удаляете не все документы, то да. Но тут есть простой выход - выбрать сначала письма без ссылок на цепочку выше. Потом уже из тех, в которых есть цепочки вниз, вытащить данные рекурсивно и удалять их внутри одного потока вместе с родителем. Тут как раз запрос не нужен, ибо степень вложенности может быть весьма обширной.

С другой стороны, а нужно ли заморачиваться всеми этими цепочками? Просто удалить все письма за промежуток дат от Х до У и не парить моск. При этом не трогать подчиненные письма - пусть живут, ибо кому они мешают?
---
если построить дерево заморачиваться и не нужно, все будет по цепочке без пересечений. Т.к. вложенностей может быть слишком много, то выйдет что на 1 поток 90% писем будет, что как видите не очень.
---
Выложил два подхода https://infostart.ru/public/622195/
Первый запуск через регламентное задание с фиксированными параметрами и запуск из формы с более гибкой настройкой.
---
Единственное, возможно ли внешней обработкой через регламентное задание делить код на куски, без использования написанного модуля в конфигурации. Это у меня не получилось пока.
Пришлось ограничить выполнения кода в 1 поток.
---
Доброго дня,
Пожалуйста, подскажите, в окончательном варианте документы-письма удаляются или помечаются на удаление?
---
в моей обработке было удаление. Т.е. мы удаляем все ссылки, а затем сам документ. Таким образом база в бекапе упала с 50 ГБ до 15Гб. Хотя может и больше. После уже письма так не грузили.
---
А какой смысл вам помечать на удаление, если цель удалить из базы.