Как устроены ключи таблиц в базе 1С 8.3: ссылки, измерения, индексы

· 10 мин

Содержание

Ключ таблицы в 1С — это набор полей, по которому платформа однозначно находит строку. У справочника и документа это поле Ссылка (уникальный идентификатор объекта), у регистра сведений — измерения плюс период и регистратор, если они есть, у регистра накопления — регистратор и номер строки. Явно объявить PRIMARY KEY, как в SQL, разработчик не может: ключ получается из того, какой объект метаданных вы создали и какие измерения ему дали.

Отсюда практический вывод. Управлять ключом в 1С 8.3 — значит правильно выбрать тип объекта, состав и порядок измерений, свойство «Индексировать» у реквизитов и индексы временных таблиц в запросах. Всё это одинаково для любой конфигурации на платформе 8.3: БП, ЗУП, УТ, ERP.

Что считается ключом таблицы в 1С и зачем он нужен

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

  • 🔎 найти запись — открыть элемент справочника, прочитать курс валюты на дату, получить движения документа;
  • 🔒 не допустить дублей — две записи регистра сведений с одинаковым набором ключевых полей не запишутся;
  • ⚡ быстро выбирать данные — по ключевым полям строится индекс, и запрос с отбором по ним не читает всю таблицу.

Пользователь сталкивается с ключом косвенно. Когда при записи регистра появляется ошибка Запись с такими ключевыми полями существует!, речь именно о ключе таблицы. Когда в документе вместо контрагента видно <Объект не найден> с длинным идентификатором в скобках — это ссылка, которая указывает на удалённую строку другой таблицы.

Посмотреть реальные имена таблиц и их индексы можно программно. Функция ПолучитьСтруктуруХраненияБазыДанных() возвращает таблицу соответствия: имя объекта метаданных, имя таблицы в СУБД (_Reference25, _Document112, _InfoRg4561 и т. п.), поля и индексы.

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

Второй параметр Истина возвращает имена полей в терминах СУБД, а не в терминах 1С.

Виды ключей в 1С: первичный, внешний и уникальный

Классическая троица из реляционных баз в 1С есть, но выглядит иначе.

Понятие SQLЧто это в 1СКто обеспечивает
Первичный ключСсылка у объектов; измерения (+ период, регистратор) у регистров сведений; регистратор + номер строки у движенийПлатформа, уникальный индекс в СУБД
Внешний ключРеквизит ссылочного типа, например Контрагент в документеТолько прикладная логика, ограничений в СУБД нет
Уникальный ключКонтроль уникальности кода и номера, набор измерений регистра сведенийПлатформа при записи объекта

Первичный ключ: Ссылка и ключ записи

Справочники, документы, планы видов характеристик, планы счетов, бизнес-процессы и задачи — ссылочные объекты. Их строка в СУБД идентифицируется полем _IDRRef (16 байт, по сути UUID). В языке 1С это Ссылка. Её можно получить строкой: Строка(Ссылка.УникальныйИдентификатор()).

Регистры ссылки не имеют. Вместо неё работает ключ записи — объект вида РегистрСведенийКлючЗаписи.КурсыВалют. Он состоит из значений ключевых полей. Именно его форма записи регистра получает в параметре Ключ, когда вы открываете запись из списка.

Табличные части хранятся в отдельной таблице. Строку там определяет ссылка на владельца плюс служебное поле ключа строки, а порядок задаёт НомерСтроки.

Внешний ключ: ссылочный реквизит

Реквизит типа СправочникСсылка.Контрагенты логически является внешним ключом. Но FOREIGN KEY в базе платформа не создаёт. СУБД не помешает удалить контрагента , на которого ссылаются документы.

Целостность держит прикладной уровень. При удалении помеченных объектов платформа ищет ссылки и не удаляет объект, на который они есть. Удаление напрямую Удалить() из кода такой проверки не делает — так и появляются «битые» ссылки.

Уникальный ключ: контроль уникальности

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

Как ключи и индексы влияют на скорость запросов в 1С

Индекс — это упорядоченная копия ключевых полей со ссылкой на строку. Если отбор в запросе совпадает с началом индекса, СУБД находит нужные строки за несколько чтений. Если не совпадает — читает таблицу целиком.

Что платформа индексирует сама:

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

Остальное — по вашему решению. У реквизита справочника или документа свойство «Индексировать» принимает три значения: «Не индексировать», «Индексировать», «Индексировать с доп. упорядочиванием». У измерения регистра — флажок «Индексировать».

Индексируйте реквизит, если по нему регулярно идёт отбор в списках или соединение в запросах, а значений много и они разные. ИНН контрагента, штрихкод, внешний идентификатор из другой системы — хорошие кандидаты. Булево поле или перечисление из трёх значений — плохие: индекс почти ничего не отсекает.

Каждый индекс замедляет запись и занимает место. На таблице, куда пишут тысячи строк в час, десяток лишних индексов заметен. Поэтому «проиндексировать всё на всякий случай» — плохая идея.

Отдельно о виртуальных таблицах регистров (Остатки, Обороты, СрезПоследних). Условие на измерения пишите в параметрах виртуальной таблицы, а не в ГДЕ. Тогда отбор применяется до расчёта, и СУБД использует индекс таблицы итогов.

Составной ключ регистра: когда нужен и как его спроектировать

В 1С почти любой ключ регистра составной. Курс валют определяется парой «Период + Валюта», цена номенклатуры — тройкой «Период + Вид цены + Номенклатура», остаток — сочетанием «Номенклатура + Склад + Партия».

Составной ключ нужен, когда одной сущности мало, чтобы назвать факт. Если на один товар бывает несколько цен разных видов, вид цены обязан быть измерением, иначе вторая цена затрёт первую.

Как выбрать измерения

  1. Сформулируйте, что именно хранит одна запись: «цена товара определённого вида на дату».
  2. Каждое существительное из этой фразы, без которого запись неоднозначна, — кандидат в измерения.
  3. Всё, что описывает запись, а не различает её (цена, валюта цены, комментарий), — ресурсы или реквизиты.
  4. Проверьте на примере: могут ли существовать две записи с одинаковыми измерениями и разными ресурсами? Если могут — измерения не хватает.

Порядок измерений имеет значение

Индекс строится по измерениям в том порядке, в каком они стоят в конфигураторе. Запрос с отбором по первому измерению использует индекс полностью, по второму без первого — хуже или вовсе нет.

Правило простое: первым ставьте измерение, по которому отбирают почти всегда. Для регистра цен это обычно вид цены или номенклатура — смотрите, какие запросы реально идут к регистру.

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

Проверка проекта нового регистра
Выполнено: 0 / 6

Ключи таблиц на примерах типовых объектов

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

Справочник «Контрагенты»

Ключ — Ссылка. Код и наименование индексируются платформой. ИНН стоит индексировать, если по нему ищут при загрузке выписок и обменах.

Документ с табличной частью «Товары»

Шапка документа — одна строка с ключом Ссылка. Табличная часть — отдельная таблица, где одна строка определяется документом и ключом строки. Поэтому запрос к Документ.РеализацияТоваровУслуг.Товары возвращает поле Ссылка — это и есть связь с шапкой.

Регистр сведений «Курсы валют»

Периодический, ключ — Период + Валюта. Записать второй курс доллара на ту же дату нельзя: запись с таким ключом уже есть, её можно только изменить.

Регистр накопления остатков

Таблица движений: ключ — Регистратор + НомерСтроки. Один документ даёт столько строк, сколько движений сделал. Таблица итогов: период и измерения. Отсюда правило: не добавляйте в регистр накопления измерения «на будущее» — каждое умножает число строк итогов.

Как работать с ключами в запросах и коде 1С

Индекс временной таблицы

Если временная таблица потом соединяется с другой по полю, проиндексируйте её по этому полю. Имя регистра ниже условное — подставьте свой.

ВЫБРАТЬ
    Остатки.Номенклатура КАК Номенклатура,
    Остатки.КоличествоОстаток КАК Остаток
ПОМЕСТИТЬ ВТ_Остатки
ИЗ
    РегистрНакопления.ОстаткиТоваров.Остатки(&Дата, Склад = &Склад) КАК Остатки

ИНДЕКСИРОВАТЬ ПО
    Номенклатура
;

ВЫБРАТЬ
    Цены.Номенклатура,
    Цены.Цена,
    ЕСТЬNULL(ВТ_Остатки.Остаток, 0) КАК Остаток
ИЗ
    РегистрСведений.ЦеныНоменклатуры.СрезПоследних(&Дата, ВидЦены = &ВидЦены) КАК Цены
        ЛЕВОЕ СОЕДИНЕНИЕ ВТ_Остатки КАК ВТ_Остатки
        ПО Цены.Номенклатура = ВТ_Остатки.Номенклатура

На сотне строк разницы не будет. На десятках тысяч индекс по полю соединения заметно ускоряет запрос.

Чтение записи регистра по ключу

МенеджерЗаписи читает ровно одну запись по полному ключу. Для периодического регистра период должен совпасть точно.

МенеджерЗаписи = РегистрыСведений.КурсыВалют.СоздатьМенеджерЗаписи();
МенеджерЗаписи.Период = НачалоДня(Дата);
МенеджерЗаписи.Валюта = Валюта;
МенеджерЗаписи.Прочитать();
Если МенеджерЗаписи.Выбран() Тогда
    Курс = МенеджерЗаписи.Курс;
КонецЕсли;

Если нужен «курс на дату», а не «курс, записанный ровно этой датой», используйте СрезПоследних — менеджер записи в этом случае ничего не найдёт.

Ключ записи для открытия формы

ЗначенияКлюча = Новый Структура("Период, Валюта", НачалоДня(Дата), Валюта);
Ключ = РегистрыСведений.КурсыВалют.СоздатьКлючЗаписи(ЗначенияКлюча);
ОткрытьФорму("РегистрСведений.КурсыВалют.ФормаЗаписи", Новый Структура("Ключ", Ключ));

Индекс таблицы значений

Поиск НайтиСтроки() по таблице значений без индекса перебирает все строки. Индекс добавляется одной строкой:

ТЗ.Индексы.Добавить("Номенклатура, Склад");
Отбор = Новый Структура("Номенклатура, Склад", Товар, Склад);
НайденныеСтроки = ТЗ.НайтиСтроки(Отбор);

Поиск в цикле по большой таблице — частая причина «зависаний» обработок. Для поиска по одному полю удобно и Соответствие: ключ — значение поля, значение — строка или сумма.

💡 Набор записей регистра, подчинённого регистратору, всегда пишется целиком по отбору: НаборЗаписей.Отбор.Регистратор.Установить(Ссылка). Отбор и есть ключ набора — без него запись заменит не то, что вы ожидаете.

Частые ошибки с ключами в 1С и как их избежать

  • ❌ Измерение сделали ресурсом. Вторая запись с другим значением этого поля затирает первую. Признак — «пропадающие» цены или настройки. Исправление — перенос поля в измерения с реструктуризацией.
  • ❌ Лишнее измерение «для отчёта». Комментарий или автор в измерениях разрешают дубли по смыслу и раздувают индекс. Такие поля — реквизиты.
  • ❌ Условие на измерения в ГДЕ вместо параметров виртуальной таблицы. Остатки считаются по всем складам, потом лишнее отбрасывается. Запрос медленный.
  • ❌ Соединение по неиндексированному полю. Например, поиск контрагента по ИНН в обмене при выключенной индексации ИНН. На большом справочнике каждая загрузка тормозит.
  • ❌ Удаление объектов из кода методом Удалить(). Ссылочная целостность не проверяется, в документах остаются <Объект не найден>. Используйте пометку удаления и штатное удаление помеченных объектов.
  • ❌ Запись набора регистра без отбора. Набор без установленного отбора в независимом регистре сведений при записи с замещением заменяет все записи регистра. Это одна из самых разрушительных ошибок в коде.

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

Частые вопросы о ключах таблиц в 1С

Можно ли в 1С создать первичный ключ по своему полю?
Нет. Для ссылочных объектов ключ — всегда Ссылка. Если нужна уникальность другого поля, используют регистр сведений, где это поле — измерение, или проверку в обработчике ПередЗаписью.
Как в 1С сделать уникальным реквизит справочника, например ИНН?
Платформа такого флажка для произвольного реквизита не даёт. Проверку пишут в модуле объекта: запрос ищет другой элемент с тем же значением, и при находке запись отменяется. Реквизит при этом стоит проиндексировать.
Чем ключ записи отличается от ссылки?
Ссылка — постоянный идентификатор объекта, не меняется при изменении реквизитов. Ключ записи регистра состоит из значений измерений: поменяли измерение — это уже другая запись с другим ключом.
Ключи доступа в 1С — это ключи таблиц?
Нет. Ключи доступа в типовых конфигурациях — механизм ограничения прав на уровне записей. К первичным ключам и индексам таблиц они отношения не имеют.
Можно ли добавить индекс в СУБД вручную, минуя конфигуратор?
Технически СУБД это позволяет, но при следующей реструктуризации платформа может пересоздать таблицу, и индекс пропадёт. Правильный путь — свойство «Индексировать» в конфигураторе.