В процессе разработки и сопровождения конфигураций на платформе «1С:Предприятие» нередко возникает ситуация, когда тип реквизита изначально был выбран избыточным. Типичный пример — использование типа Строка неограниченной длины для полей, которые по логике бизнес-процесса не должны превышать определенного лимита (например, наименование номенклатуры, контрагента или внутреннего документа).
В этой статье мы подробно разберем, к каким техническим последствиям ведет изменение типа строки с неограниченной на ограниченную (например, до 160 символов), как ведет себя СУБД при реструктуризации, с какими сложностями можно столкнуться при написании запросов и как решить задачу ограничения ввода программными методами без изменения метаданных.
Когда мы изменяем тип реквизита в конфигураторе с неограниченной строки на строку фиксированной или ограниченной длины, платформа запускает процесс реструктуризации таблиц базы данных. Физическое хранение информации в СУБД при этом кардинально меняется, что имеет свои плюсы и минусы в зависимости от используемого варианта работы.
Рассмотрим, как ведут себя различные СУБД:
Строку(160) переносит хранение данных непосредственно в основную таблицу записей, что предотвращает переполнение BLOB-файла и повышает стабильность системы.Строку(160) транслирует реквизит в стандартный тип данных NVARCHAR(160). Данные начинают храниться непосредственно «внутри строки» таблицы (In-Row). Это существенно ускоряет выполнение запросов SELECT, снижает нагрузку на дисковую подсистему и оптимизирует кэш СУБД.Важное предупреждение: В процессе реструктуризации СУБД автоматически обрежет все существующие строки, превышающие 160 символов. Все символы, начиная со 161-го, будут безвозвратно утеряны. Если среди этих записей хранятся важные идентификаторы, артикулы или уникальные коды, это может привести к нарушению логики учета.
Строки неограниченной длины накладывают жесткие ограничения на использование языка запросов 1С. Разберем основные проблемы и пути их решения:
СГРУППИРОВАТЬ ПО и ПОДИТОГИ. Также по таким полям невозможно выполнять операции соединения таблиц.
ВЫБРАТЬ
ВЫРАЗИТЬ(СпрНоменклатура.Наименование КАК СТРОКА(160)) КАК НаименованиеОграниченное,
СУММА(Продажи.Количество) КАК Количество
ИЗ
РегистрНакопления.Продажи КАК Продажи
ЛЕВОЕ СОЕДИНЕНИЕ Справочник.Номенклатура КАК СпрНоменклатура
ПО Продажи.Номенклатура = СпрНоменклатура.Ссылка
СГРУППИРОВАТЬ ПО
ВЫРАЗИТЬ(СпрНоменклатура.Наименование КАК СТРОКА(160))
Здесь важно помнить о лимитах платформы: максимальная длина, которую можно указать в функции ВЫРАЗИТЬ для строки, ограничена 1024 символами. Попытка указать большую длину приведет к синтаксической ошибке на этапе компиляции запроса. Кроме того, в зависимости от настроек СУБД, функция ВЫРАЗИТЬ может дополнять короткие строки пробелами до указанной длины (например, строка "Тест" превратится в строку из 160 символов, где 156 символов — пробелы справа), что увеличивает объем передаваемого трафика.
Альтернативой является функция ПОДСТРОКА(Поле, 1, 160). Она возвращает исходную длину строки, если она короче лимита. Однако стандарт разработки 1С рекомендует использовать именно ВЫРАЗИТЬ для приведения типов перед группировкой, так как это гарантирует более предсказуемое поведение оптимизатора запросов СУБД.
Реквизиты неограниченной длины принципиально невозможно индексировать. Любой поиск по такому полю в базе данных будет выполняться методом полного сканирования таблицы (Full Table Scan), что при больших объемах данных (сотни тысяч и миллионы записей) приводит к катастрофическому падению производительности.
После изменения типа на Строку(160) у разработчика появляется возможность установить свойство реквизита «Индексировать» (или «Индексировать с дополнительным упорядочиванием»). Это кардинально ускоряет:
Если мы приняли решение изменить метаданные в конфигураторе, нельзя полагаться на автоматическое усечение строк СУБД. Проанализируем правильный алгоритм действий:
Шаг 1. Поиск проблемных записей. Напишем запрос, который определит количество элементов, длина которых превышает целевые 160 символов, и выведем их список для анализа:
ВЫБРАТЬ
Ссылка КАК ПроблемныйЭлемент,
Наименование КАК ИсходноеЗначение,
ДЛИНА_СТРОКИ(Наименование) КАК Длина
ИЗ
Справочник.Номенклатура
ГДЕ
ДЛИНА_СТРОКИ(Наименование) > 160
Шаг 2. Корректировка данных. Необходимо создать обработку, которая позволит ответственному пользователю или администратору вручную скорректировать данные (сократить наименования без потери ключевого смысла), либо программно обрезать строки по определенным правилам (например, сохраняя важные артикулы в конце строки). Только после того как запрос вернет 0 строк, можно безопасно запускать реструктуризацию в конфигураторе.
Что делать, если реструктуризация нежелательна (например, база данных слишком большая, процесс займет много часов простоя, или существующие длинные записи критически важны и не должны изменяться)? В этом случае мы можем настроить программный контроль ввода для новых и изменяемых записей.
Решение состоит из двух рубежей контроля: на уровне бизнес-логики (перед записью объекта) и на уровне интерфейса (ограничение ввода на форме).
Разместим код проверки в модуле соответствующего объекта (справочника, документа или бизнес-процесса). Это гарантирует, что некорректные данные не попадут в базу ни через форму, ни при программной записи (например, через интеграцию или загрузку данных):
Процедура ПередЗаписью(Отказ)
// Исключаем проверку при обмене данными, если это необходимо
Если ОбменДанными.Загрузка Тогда
Возврат;
КонецЕсли;
МаксимальнаяДлина = 160;
ТекущаяДлина = СтрДлина(Наименование);
Если ТекущаяДлина > МаксимальнаяДлина Тогда
Отказ = Истина;
ОбщегоНазначенияКлиентСервер.СообщитьПользователю(
НСтр("ru = 'Длина наименования не может превышать " + МаксимальнаяДлина + " символов (сейчас " + ТекущаяДлина + ").'"),
,
"Наименование"
);
КонецЕсли;
КонецПроцедуры
Чтобы пользователь не получал раздражающие сообщения об ошибке уже после заполнения всей формы, ограничим возможность ввода символов сверх лимита прямо в поле ввода. Для этого в модуле формы настроим ограничение типа.
Если конфигурация разработана на базе Библиотеки Стандартных Подсистем (БСП), применим следующий код в обработчике ПриСозданииНаСервере:
&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
// Ограничение ввода для конфигураций на базе БСП
Элементы.Наименование.ОграничениеТипа = ОбщегоНазначения.ОписаниеТипаСтрока(160);
КонецПроцедуры
Если БСП не используется, создадим квалификатор строки вручную через описание типов:
&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
// Универсальный способ создания описания типа строки с ограничением длины
МассивКвалификаторов = Новый КвалификаторыСтроки(160, ДопустимаяДлина.Переменная);
НовоеОписаниеТипов = Новый ОписаниеТипов("Строка", , МассивКвалификаторов);
Элементы.Наименование.ОграничениеТипа = НовоеОписаниеТипов;
КонецПроцедуры
После установки свойства ОграничениеТипа платформа автоматически заблокирует нажатие клавиш на клавиатуре, как только пользователь введет 160-й символ в поле формы. При этом старые записи, длина которых превышает 160 символов, останутся в базе данных нетронутыми.
Выбор метода зависит от масштаба базы данных и долгосрочных целей разработки. Если база имеет средний размер и критически важна производительность поиска и группировок — лучшим решением будет изменение типа реквизита в метаданных конфигуратора с предварительным очищением и подготовкой данных. Если же база огромная, а изменения структуры нежелательны — используйте программное ограничение ввода на форме в сочетании с жесткой валидацией в событии ПередЗаписью.