В процессе разработки и сопровождения конфигураций на платформе 1С:Предприятие 8.3 программисты иногда сталкиваются с необходимостью изменения метаданных существующих объектов. Одной из таких задач является смена типа кода справочника, например, с типа Строка на тип Число. Казалось бы, простая операция в конфигураторе может привести к серьезной проблеме: при попытке записи нового элемента или вызове метода УстановитьНовыйКод() сеанс пользователя полностью зависает. Рассмотрим подробно, почему это происходит и как правильно диагностировать и устранить данную неисправность.
Когда мы меняем тип кода, платформа должна полностью перестроить логику генерации новых значений. Проблема зависания в версии 8.3.14 и выше чаще всего связана не с самой записью данных, а с работой сервиса нумерации в кластере 1С и механизмом блокировок в СУБД. Разберем основные факторы, которые приводят к «мертвому» зависанию:
rmngr. После изменения типа данных в метаданных старый строковый кэш может конфликтовать с новыми числовыми требованиями.SELECT MAX может вызвать эксклюзивную блокировку таблицы REFLOCK, ожидая завершения неопределенного процесса.Прежде чем переходить к настройкам сервера, исключим вероятность зацикливания кода. Проанализируем обработчики событий, которые срабатывают при установке нового кода. Нам необходимо проверить:
ПриУстановкеНовогоКода в модуле объекта справочника.ПриУстановкеНовогоКода для данного справочника или для всей группы объектов.Для диагностики выполним замер производительности. Если при вызове метода УстановитьНовыйКод() замер показывает бесконечное выполнение одной и той же строки или просто «пропадает» в системных функциях, следует временно закомментировать содержимое обработчиков. Рассмотрим типичный пример опасного кода, который может вызвать проблемы при смене типа:
Процедура ПриУстановкеНовогоКода(СтандартнаяОбработка, Префикс)
// Если здесь происходит рекурсивный вызов или сложная логика
// поиска кода вручную, это может привести к зависанию.
Если ТипЗнч(ЭтотОбъект.Код) = Тип("Строка") Тогда
// Старая логика, которая больше не актуальна для числового кода
КонецЕсли;
КонецПроцедуры
Если программный код чист, нам необходимо понять, на каком этапе «спотыкается» SQL-сервер. Для этого проанализируем лог технологического журнала. Типичная последовательность команд при генерации кода выглядит следующим образом:
BEGIN TRANSACTION.Regions=ReferenceX.REFLOCK, Locks='ReferenceX.REFLOCK Exclusive'.
SELECT MAX(T1._Code)
FROM _Reference142 T1
Разберем ситуацию: если в колонке _Code остались данные, которые некорректно преобразовались из строки в число (например, содержали лидирующие пробелы или спецсимволы), функция MAX() может выполняться крайне медленно, вызывая Full Table Scan. В этом случае мы увидим в ТЖ событие DBV8DBPostgreSQL или DBMSSQL с длительным временем выполнения и последующим TTIMEOUT.
Как показывает практика (сообщение 5 и 6 форума), самым быстрым решением часто является рестарт службы кластера серверов 1С:Предприятия. Это необходимо для полной очистки кэша сервиса нумерации.
Однако, если перезагрузка всего кластера невозможна (рабочая база с множеством пользователей), попробуем применить «мягкий» способ сброса нумерации:
Этот цикл действий заставляет платформу обновить записи в системных таблицах (таких как _Numbering), которые отвечают за хранение последнего выданного номера.
Проанализируем состояние данных в таблице справочника. Даже если через интерфейс 1С справочник кажется пустым, в базе данных могут существовать «битые» записи. Выясним причину, выполнив запрос через консоль запросов 1С с установленным флагом «Выбирать удаленные» (если используется механизм удаления объектов) или напрямую через SQL Management Studio.
Проверим наличие записей, где код не может быть приведен к числу. Рассмотрим пример SQL-запроса для поиска таких проблемных мест (для MS SQL):
SELECT _IDRRef, _Code
FROM _Reference142
WHERE ISNUMERIC(_Code) = 0
Если такие записи найдены, их необходимо либо удалить, либо исправить их код на корректное числовое значение. После внесения изменений обязательно выполним обновление статистики и реиндексацию таблицы в СУБД. Это критически важно, так как старые индексы, построенные для строковых данных, могут мешать оптимизатору запросов после смены типа колонки на числовой.
Финальным этапом восстановления нормальной работы справочника будет запуск штатной процедуры «Тестирование и исправление». В окне настройки выберем следующие пункты:
Важный момент: если база файловая, перед запуском ТиИ обязательно воспользуемся утилитой chdbfl.exe, которая проверит физическую целостность файла 1Cv8.1CD. При смене типов данных физическая структура таблицы могла быть повреждена, что и вызывает зависание при попытке записи.
Подводя итог, можно сказать, что зависание при вызове УстановитьНовыйКод() — это комплексная проблема, возникающая на стыке кэширования платформы и производительности СУБД.
Рассмотрим краткий алгоритм действий при возникновении подобной ситуации:
ПриУстановкеНовогоКода и подписках.Соблюдение этой последовательности позволит избежать использования «костылей» в коде и вернет штатную работу механизма автонумерации справочника.