Попробуем рассмотреть кратко, что такое хранилище сеансовых данных.
Хранилище сеансовых данных — каталог на сервере «1С:Предприятие», которому установлено требование назначения функциональности «Сервис сеансовых данных». Если требования функциональности нет, то сеансовые данные распределяются по всем рабочим серверам.
Расположение каталога сеансовых данных можно определить по ключу «/d» в командной строке запуска службы сервера.
Обычно это файлы C:\Program Files (x86)\1cv8\srvinfo\reg_номерпорта\snccntx[guid]\snccntx*.dat .
Сеансовые данные образуются не только методами «ПоместитьВоВременноеХранилище», «ПоместитьФайл», «НачатьПомещениеФайла», но и в результате работы формы: после ввода значений в поля ввода, при последующих серверных вызовах, данные сбрасываются в хранилище сеансовых данных.
Хранилище сеансовых данных параллельно существует и в памяти операционной системы. С помощью технологии mapping данные файлов snccntx*.dat частично, в необходимом размере, отображаются в оперативную память.
Сеансовые данные постепенно устаревают — при закрытии формы, сеанса пользователя или при следующем серверном вызове. Это зависит от способа помещения данных в хранилище сеансовых данных.
Неактуальные сеансовых данные периодически очищаются сборщиком мусора. Если помещаемые данные содержат циклические ссылки, то автоматической очистки может не произойти.
Объём создаваемых сеансовых данных можно определить с помощью анализа технологического журнала. Для этого требуется включить сбор событий CALL, SCALL и CONN со следующими настройками:
Вопрос имеет несколько решений в зависимости от версии платформы 1С и режима управления блокировкой данных в конфигурации.
В версии платформы <8.2.14 константы хранятся в одной таблице _Consts в одной строке в разных колонках:
Начиная с 1С 8.2.14 для каждой константы определена отдельная таблица:
Рассмотрим, какие блокировки будут накладываться при чтении в транзакции и вне транзакции в СУБД MS SQL 2014 при автоматическом режиме управления блокировкой данных:
1С 8.2.13
Чтение константы в транзакции методом Получить() в автоматическом режиме
Установлена разделяемая блокировка (S) на единственную запись в кластерном индексе _Consts_ByKey_B таблицы _Consts, а также блокировки намерения IS на страницу индекса _Consts_ByKey_B и на всю таблицу.
1С 8.2.13
Чтение константы в транзакции запросом в автоматическом режиме
Установлена разделяемая блокировка диапазона RangeS-S на единственную запись кластерного индекса _Consts_ByKey_B, блокировки намерения IS на страницу кластерного индекса _Consts_ByKey_B и на всю таблицу.
Переведём конфигурацию в управляемый режим, включим в ТЖ отслеживание событий TLOCK и SDBL к исследуемой базе. Проведём аналогичный эксперимент по чтению в транзакции константы методом Получить() и запросом.
После выполнения запроса установленных управляемых блокировок 1С и блокировок СУБД не зафиксировано.
Во время работы метода Получить() и выполнения запроса на строки, выбираемые запросом, накладывалась S-блокировка. После чтения строк данная блокировка снималась.
Изменим версию совместимости на 8.2.16. Повторим эксперимент в автоматическом режиме:
1С 8.2.16
Чтение константы в транзакции методом Получить() в автоматическом режиме
Установлена S-блокировка на запись кластерного индекса _Const1832_ByKey_B, блокировки намерения IS на страницу кластерного индекса и на всю таблицу. Видно, что для каждой константы используется своя таблица.
1С 8.2.16
Чтение константы в транзакции запросом в автоматическом режиме
Установлена разделяемая блокировка диапазона RangeS-S на единственную запись кластерного индекса _Const1832_ByKey_B, блокировки намерения IS на страницу кластерного индекса _Consts_ByKey_B и на всю таблицу.
При использовании платформы 8.3 без режима совместимости с 8.2 в управляемом режиме блокировок чтение в транзакции и без транзакции неблокирующее, вследствие использования уровня изоляции Read Commited Snapshot (RCS).
В автоматическом режиме блокировок в 8.3 без режима совместимости с 8.2 будут наложены аналогичные S и RangeS-S-блокировки, как и в 8.2 (см. иллюстрации выше).
В случае, если транзакции не используются, чтение в 8.2.13, 8.2.14 и 8.3 будет неблокирующее.
Таким образом, можно заполнить следующую таблицу-ответ на вопрос билета 1:
Действие 1
Действие 2
8.2.13
8.2.14
8.3
Запись Конст1
Запись Конст2
—
+
+
Чтение Конст1
Запись Конст2
—
+
+
Чтение Конст1
Чтение Конст2
+
+
+
Вопрос 1.2
Ответ на вопрос зависит от режима управления блокировкой в конфигурации и от версии платформы.
В случае автоматического режима и платформы 8.2 будет следующая картина:
// метод Записать() преобразовал разделяемые блокировки в исключительные. В итоге установлены:
// 1. Исключительная X-блокировка на запись некластерного индекса _Reference7_ParentDescr_RLSR.
// 2. Исключительная X-блокировка на запись дополнительного некластерного индекса с учётом иерархии _Reference7_ByParentField24_RLSSRL (создан вручную для одного из реквизитов).
// 3. Исключительная X-блокировка на запись некластерного индекса _Reference7_Descr_SR.
// 4. Исключительная X-блокировка на запись кластерного индекса PK___Referen__AC8ED0C499C42AD1.
// 5. Исключительная X-блокировка запись дополнительного некластерного индекса без учёта иерархии _Reference7_ByField25_SSRL (создан вручную для одного из реквизитов).
// 6. Блокировки намерения IX на страницу индексов _Reference7_ParentDescr_RLSR, _Reference7_ByParentField24_RLSSRL, _Reference7_Descr_SR, PK___Referen__AC8ED0C499C42AD1, _Reference7_ByField25_SSRL.
// 7. Блокировка намерения IX на всю таблицу справочника.
// 8. Разделяемая блокировка намерения IS на страницу индекса табличной части _Reference7_VT1763_IntKeyInd.
// 9. Разделяемая блокировка намерения IS на таблицу табличной части.
ЗафиксироватьТранзакцию();
// метод ЗафиксироватьТранзакцию() снял все установленные блокировки.
КонецПроцедуры
Разделяемые блокировки после метода ПолучитьОбъект() в автоматическом режиме
Исключительные блокировки после метода Записать() в автоматическом режиме
Поведение платформы в автоматическом режиме на платформе 8.3 будет аналогично.
// а также блокировки намерения IX на страницы этих же индексов и IX-блокировку на всю таблицу справочника.
// Также установлена управляемая блокировка 1С на пространство Reference7.REFLOCK.
ЗафиксироватьТранзакцию();
// метод ЗафиксироватьТранзакцию() снял все установленные блокировки СУБД и управляемую блокировку 1С
КонецПроцедуры
Исключительные блокировки в управляемом режиме после метода Записать()
Также в управляемом режиме при выполнении метода Записать() установилась управляемая блокировка на пространство Reference7.REFLOCK .
Данный код может привести к взаимоблокировке с видом «повышение уровня изоляции ресурса» вследствие следующих действий:
Если две параллельные транзакции в автоматическом режиме установят разделяемую S-блокировку на один и тот же ресурс, выполнив запрос в транзакции (методом ПолучитьОбъект()), то в последствии каждая транзакция будет вынуждена ждать другую для установки исключительной X-блокировки. Менеджер блокировок СУБД распознает это и возникнет взаимоблокировка.
Взаимоблокировка СУБД вследствие повышения уровня изоляции ресурса
Для решения проблемы взаимоблокировки можно пойти несколькими путями:
Получать ссылку на объект номенклатуры запросом с опцией для ИЗМЕНЕНИЯ. Например, так:
Перевести конфигурацию в управляемый режим блокировок. В этом случае разделяемая S-блокировка будет снята в процессе выполнения запроса после чтения строк данных (для 8.2) и не будет установлена вообще (для 8.3).
Использовать методы объектной блокировки (для интерактивного режима). В этом случае метод Заблокировать() вызовет исключение, если данный объект уже заблокирован другим пользователем:
Особенностями автоматического режима управления блокировкой данных является следующее:
При чтении запросом с опцией для ИЗМЕНЕНИЯ пустой таблицы будет заблокирована RangeS-U-блокировкой пустая запись индекса. любая другая запись будет «соседней» для пустой записью и не может быть вставлена в таблицу.
Блокировка на соседних записях в регистре также вызвана особенностью Range-блокировок, которые не только блокируют считанный/записанный диапазон, но и ещё одну строку ниже этого диапазона.
Для решения указанных проблем требуется перевод конфигурации в управляемый режим, в котором нет Range-блокировок.
Для этого нужно выполнить следующие действия:
Сделать копию рабочей базы.
В копии рабочей базы установить свойство «Режим управления блокировкой» в значение «Управляемый».
Найти в коде конфигурации все места, где выполняется чтение итогов регистра и последующая запись в этот регистр.
Использовать в этих местах исключительную управляемую блокировку 1С на записываемые данные или использовать новую методику проведения (сначала записывать данные, потом контролировать итоги по регистру). В последнем случае рассмотреть возможность использования разделения итогов и опции БлокироватьДляИзменения набора записей.
В ходе теста оценки производительности данный сокращенный способ добавления строк в таблицу значений на платформе 8.3.6.2530 работает на 16.45% быстрее.