Почему 1С использует тип binary в MS SQL и как устроена структура таблиц базы данных

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

При анализе структуры базы данных 1С:Предприятие на стороне MS SQL Server многие разработчики задаются вопросом: почему архитекторы платформы отказались от стандартных типов данных, таких как uniqueidentifier или bit, в пользу универсального binary? На первый взгляд это кажется избыточным усложнением, однако за таким решением стоят серьезные архитектурные причины, связанные с производительностью, кроссплатформенностью и историей развития платформы. В этой статье мы подробно разберем, как именно 1С хранит данные на уровне СУБД и какие преимущества это дает.

Особенности хранения уникальных идентификаторов (GUID)

Разберем ситуацию с типом uniqueidentifier. В MS SQL Server для хранения ссылок 1С использует binary(16). Основная причина кроется в механизме индексации. Стандартные GUID в Windows генерируются не последовательно. Если бы 1С записывала их в базу «как есть» в индексированное поле, это приводило бы к катастрофической фрагментации индексов при каждой вставке новой записи. Новые узлы B-дерева вставлялись бы в случайные места, вызывая постоянную перестройку страниц данных.

Проанализируем решение, которое применила 1С: платформа использует свой собственный алгоритм «переворачивания» байтов GUID. Наиболее часто меняющиеся части идентификатора переносятся в конец последовательности, а более стабильные — в начало. Благодаря этому новые записи в базе данных чаще попадают в конец индекса. Это значительно ускоряет операции записи и снижает нагрузку на дисковую подсистему, так как SQL-серверу не нужно постоянно переупорядочивать данные внутри страниц.

Выясним причину, почему не используется uniqueidentifier с функцией NEWSEQUENTIALID(). Ответ прост: 1С должна обеспечивать идентичное поведение на разных СУБД (PostgreSQL, Oracle, IBM DB2). Реализация собственной логики перестановки байтов на уровне платформы позволяет гарантировать стабильную производительность независимо от того, какой SQL-сервер выбрал клиент.

Бинарные поля для булевых значений и простых типов

Рассмотрим, почему для булевых значений часто используется binary(1) вместо стандартного bit. Рассмотрим основные факторы:

  1. Унификация кода трансляции: Разработчики платформы стремятся к тому, чтобы генератор SQL-запросов (L-язык) работал максимально одинаково для всех СУБД. Использование 0x00 для Ложь и 0x01 для Истина в бинарном поле проще транслировать в запросы, которые поймут и Oracle, и PostgreSQL без специфических диалектов.
  2. Избегание проблем с NULL: В концепции 1С поля данных практически никогда не принимают значение NULL (за исключением результатов соединений). Поля всегда инициализируются значениями по умолчанию. Использование бинарного типа позволяет платформе жестко контролировать содержимое поля, не полагаясь на особенности обработки NULL конкретной СУБД.
  3. Историческое наследие: Как отмечалось в обсуждениях, изначально планировалось внедрение «троичной логики» (Истина, Ложь, Неопределено) на уровне хранения, и бинарный тип лучше всего подходил для расширения набора состояний в будущем.

Хранение составных типов данных

Проанализируем ситуацию, когда реквизит имеет составной тип (например, «ДокументОбъект» или «СправочникСсылка»). В этом случае 1С не может создать одну колонку в SQL. Вместо этого создается несколько полей, среди которых обязательно присутствует бинарное «поле типа».

Посмотрим на пример структуры в SQL для составного типа:

  1. Поле _TYPE (бинарное): содержит внутренний код типа метаданных.
  2. Поля для хранения значений: _RRef (ссылка), _N (число), _S (строка) и так далее.

Именно по байтовому коду в поле типа платформа понимает, из какой именно параллельной колонки нужно считать данные в конкретный момент. Это позволяет реализовать гибкость метаданных 1С поверх строгой типизации SQL-таблиц.

Получение уникального идентификатора в запросах

Долгое время получение GUID напрямую через SQL-запрос было нетривиальной задачей из-за того самого «перевернутого» формата 1С. Однако, начиная с версии платформы 8.3.22, разработчики получили штатный механизм. Теперь нет необходимости вручную переставлять байты с помощью SUBSTRING в прямых SQL-запросах.

Разберем пример кода на языке запросов 1С для получения строкового представления GUID:


ВЫБРАТЬ
    Номенклатура.Ссылка КАК Ссылка,
    УникальныйИдентификатор(Номенклатура.Ссылка) КАК GUID_Строкой
ИЗ
    Справочник.Номенклатура КАК Номенклатура

Платформа автоматически транслирует функцию УникальныйИдентификатор() в соответствующий SQL-код, который учитывает специфику хранения binary(16) и возвращает понятную строку. Это значительно упрощает интеграцию и выгрузку данных во внешние системы.

Системные поля и версионирование

Важно помнить о поле _Version, которое присутствует почти в каждой объектной таблице. В MS SQL оно имеет тип rowversion (или timestamp), что также является бинарным числом. Платформа использует его для реализации оптимистической блокировки. Перед записью объекта 1С проверяет, не изменилось ли значение _Version в базе данных по сравнению с тем, которое было прочитано при открытии формы. Если значения не совпадают, система выдает ошибку «Данные были изменены или удалены другим пользователем».

Идентификаторы метаданных и их хранение

Многие задаются вопросом: почему нельзя просто SQL-запросом получить имя таблицы? Дело в том, что соответствие между объектами метаданных (например, Справочник.Контрагенты) и физическими таблицами (например, _Reference42) хранится в системных таблицах Config и DBSchema. Эти данные упакованы во внутренние бинарные форматы (зачастую это сжатые XML-структуры). Платформа расшифровывает их при запуске и кэширует, поэтому прямой доступ к ним через стандартные средства SQL без знания алгоритмов декомпрессии невозможен.

Таким образом, использование типа binary в 1С — это не «квадратные колеса», а выверенное инженерное решение, позволяющее системе оставаться производительной при огромных объемах данных и сохранять независимость от конкретного вендора СУБД.

← На главную