Как устроена база данных 1С: Справочники, Перечисления, Константы и Составные типы на уровне СУБД

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

При разработке и оптимизации систем на платформе 1С:Предприятие 8 программисты часто сталкиваются с необходимостью понимать, как именно высокоуровневые объекты метаданных транслируются в физическую структуру таблиц СУБД (будь то MS SQL Server, PostgreSQL, IBM DB2 или Oracle). Существует множество мифов — например, о том, что перечисление на уровне СУБД является простым текстовым полем внутри другой таблицы, или о том, что для каждой константы создается отдельная таблица.

В этой статье мы подробно разберем реальную физическую структуру СУБД для платформы 1С 8.х. Мы выясним, как устроены перечисления, где на самом деле хранятся константы, каким образом СУБД справляется с составными типами данных и как эти знания помогают писать более производительные запросы.

Инструменты для анализа структуры базы данных

Прежде чем погрузиться в теорию, рассмотрим, как мы можем на практике увидеть структуру таблиц нашей информационной базы. Платформа 1С предоставляет для этого встроенный программный инструмент — метод ПолучитьСтруктуруХраненияБазыДанных(). Этот метод возвращает таблицу значений с описанием всех таблиц и полей СУБД, которые соответствуют объектам метаданных нашей конфигурации.

Давайте посмотрим на пример кода, с помощью которого можно выгрузить эту структуру для анализа:


ТаблицаСтруктуры = ПолучитьСтруктуруХраненияБазыДанных();
Для Каждого СтрокаТаблицы Из ТаблицаСтруктуры Цикл
    Сообщить("Объект метаданных: " + СтрокаТаблицы.ИмяМетаданных 
        + " -> Таблица в SQL: " + СтрокаТаблицы.ИмяТаблицыХранения);
КонецЦикла;

Используя этот инструмент, мы можем сопоставить любой объект в конфигураторе с реальной физической таблицей в SQL.

1. Как хранятся перечисления: таблица или поле?

Существует заблуждение, что перечисление (ПеречислениеСсылка) — это просто текстовое или числовое поле в таблице того объекта, который на него ссылается. На самом деле это принципиально не так.

На уровне СУБД каждое перечисление имеет свою собственную физическую таблицу. Если в вашей конфигурации создано перечисление СтатусыЗаказов, платформа выделит под него отдельную таблицу.

Имя таблицы: Таблицы перечислений именуются по шаблону _Enum<n>, где <n> — это внутренний уникальный порядковый номер объекта метаданных в конфигурации.

Структура таблицы перечисления: эта таблица является максимально облегченной и содержит всего два поля:

  1. _IDRRef — уникальный идентификатор конкретного значения перечисления. Это поле имеет тип данных binary(16) (UUID в двоичном формате).
  2. _EnumOrder — числовое поле (индекс), определяющее порядок сортировки элементов перечисления. Этот порядок соответствует тому, как вы расположили элементы перечисления в дереве метаданных в конфигураторе.

Важная особенность: в СУБД вы никогда не найдете текстовых названий элементов перечисления (таких как "Новый", "ВРаботе", "Выполнен"). Все эти синонимы и имена зашиты в конфигурацию платформы. Сама СУБД оперирует исключительно бинарными идентификаторами _IDRRef и порядком сортировки _EnumOrder. Платформа сопоставляет UUID из базы данных с метаданными "на лету" при выводе интерфейса пользователю.

Когда вы указываете реквизит с типом "ПеречислениеСсылка" в справочнике или документе, в таблице этого документа просто создается поле типа binary(16), в которое записывается ссылка на соответствующий UUID из таблицы _Enum<n>.

2. Как хранятся константы в 1С:Предприятии 8

Если вспомнить старые версии платформы (например, 1С 7.7), там архитектура хранения констант была иной. В версии 1С 8.х разработчики применили красивое и эффективное решение. Отдельные таблицы под каждую константу не создаются, так как это плодило бы огромное количество мелких таблиц и перегружало бы системный каталог СУБД.

Вместо этого в базе данных создается одна общая таблица _Consts.

Исключением из этого правила являются только те константы, у которых в конфигураторе созданы подчиненные табличные части. Для хранения данных таких табличных частей платформа генерирует отдельные подчиненные таблицы формата _ConstsVT<n>, которые связываются с основной таблицей констант.

3. Хранение составных типов данных в СУБД

Вопрос хранения составных типов данных (когда один реквизит может принимать значения разных типов, например, "Число", "Строка", "СправочникСсылка.Контрагенты" или "ДокументСсылка.Реализация") вызывает больше всего вопросов у начинающих разработчиков. Создаются ли для этого дополнительные таблицы связей?

Нет, составной тип данных не создает отдельных таблиц. Вместо этого платформа расширяет структуру таблицы того объекта, в котором объявлен этот реквизит, создавая несколько физических полей под один логический реквизит.

Для каждого реквизита составного типа платформа генерирует набор полей с одинаковым префиксом (например, _Fld123), но с разными суффиксами, отвечающими за хранение конкретных типов данных:

Давайте разберем наглядный пример: у нас есть реквизит ДокументОснование с составным типом, который может принимать значения: Число, Строка или СправочникСсылка.Контрагенты. В физической таблице СУБД под этот один реквизит будет выделено пять полей:

  1. _Fld123_TYPE (код типа данных в текущей строке)
  2. _Fld123_N (значение, если записано число)
  3. _Fld123_S (значение, если записана строка)
  4. _Fld123_RTRef (идентификатор таблицы справочника Контрагенты, если записана ссылка)
  5. _Fld123_RRef (UUID конкретного контрагента из таблицы контрагентов)

Когда вы записываете в этот реквизит число 150, платформа заполняет поле _Fld123_TYPE кодом типа "Число", а в поле _Fld123_N записывает значение 150. Остальные поля (_S, _RTRef, _RRef) остаются пустыми (заполняются дефолтными значениями SQL NULL или пустыми ссылками).

Влияние составных типов на производительность запросов

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

Когда СУБД выполняет запрос с соединением по составному полю, ей приходится на низком уровне анализировать множество колонок и использовать сложные логические конструкции CASE WHEN. Схематично SQL-запрос, генерируемый платформой 1С при обращении к составному полю, выглядит примерно так:


SELECT 
    CASE 
        WHEN T1._Fld123_TYPE = 0x08 THEN T2._Description -- Если это ссылка на справочник
        WHEN T1._Fld123_TYPE = 0x02 THEN T1._Fld123_S     -- Если это строка
        ELSE NULL 
    END AS ЗначениеРеквизита
FROM _Document100 T1
LEFT OUTER JOIN _Reference50 T2 ON T1._Fld123_RRef = T2._IDRRef AND T1._Fld123_RTRef = 0x00000032

Подобные конструкции существенно усложняют построение плана запроса оптимизатором СУБД. Это может приводить к сканированию таблиц (Table Scan / Index Scan) вместо быстрого поиска по индексу (Index Seek), что фатально сказывается на скорости работы системы при больших объемах данных.

Рекомендация: старайтесь избегать избыточных составных типов. Если реквизит может ссылаться только на один конкретный справочник, указывайте в конфигураторе жесткий тип, а не оставляйте составной тип "на всякий случай". Это позволит СУБД создать ровно одно поле ссылки и строить максимально эффективные индексы и планы запросов.

← На главную