Регистры 1С изнутри: где лежат данные и как их пишет документ
Содержание
Регистр в 1С — это таблица, куда система складывает факты учёта в разрезе нужных аналитик: что, где, сколько и когда. Документ сам по себе ничего не «знает» про остатки. При проведении он записывает строки (движения) в регистры, а отчёты читают уже регистры, а не документы.
На платформе 1С:Предприятие 8.3 есть три вида регистров, с которыми сталкивается любой разработчик: регистр сведений , регистр накопления и регистр бухгалтерии . Четвёртый, регистр расчёта, нужен только для зарплатных расчётов и здесь не разбирается.
Из чего состоит регистр и как он хранится в базе
У любого регистра одна и та же «анатомия». Её задают в конфигураторе на вкладке «Данные» объекта.
- 📐 Измерения — разрезы учёта: номенклатура, склад, организация, контрагент. По ним группируют и отбирают данные.
- 🔢 Ресурсы — то, что считают или хранят: количество, сумма, курс, цена.
- 🏷️ Реквизиты — дополнительная информация о записи. Итоги по ним не считаются, отбирать по ним медленнее.
- 🕒 Стандартные реквизиты —
Период,Регистратор,НомерСтроки,Активность, у регистра накопления ещёВидДвижения.
Физические таблицы
В СУБД (MS SQL, PostgreSQL) или в файловой базе каждому регистру соответствует отдельная таблица. Её имя видно по префиксу:
| Вид регистра | Таблица записей | Таблицы итогов |
|---|---|---|
| Регистр сведений | _InfoRg… | у периодического — отдельная таблица среза последних, если включена её поддержка |
| Регистр накопления | _AccumRg… | _AccumRgT… (итоги) |
| Регистр бухгалтерии | _AccRg… | _AccRgAT… (итоги по счетам) и сопутствующие таблицы для субконто |
Узнать точное имя таблицы для конкретного регистра можно функцией ПолучитьСтруктуруХраненияБазыДанных(). Она возвращает соответствие «объект метаданных → имя таблицы и полей».
Писать в эти таблицы напрямую через SQL нельзя. Платформа держит согласованными записи, итоги и кэши, и прямое изменение ломает эту связь. Читать для диагностики — можно, менять — только средствами 1С.
Регистратор и набор записей
Большинство регистров подчинены регистратору — документу. Все строки, которые документ записал, образуют набор записей с отбором по этому документу. При перепроведении платформа не правит отдельные строки: она удаляет старый набор целиком и пишет новый. Поэтому движения документа всегда отражают его текущее состояние.
Регистр сведений: хранение значений с привязкой ко времени
Регистр сведений хранит не суммы, а значения в разрезе измерений. Классические примеры — курсы валют, цены номенклатуры, учётная политика организации, ставки.
Периодический и непериодический
| Свойство | Как работает | Пример |
|---|---|---|
| Непериодический | Одна запись на комбинацию измерений | Соответствие склада и ответственного |
| Периодический (секунда, день, месяц, квартал, год) | Запись привязана к периоду, история сохраняется | Курсы валют по дням |
| По позиции регистратора | Период — момент времени документа | Цены, установленные документом |
Ключ уникальности периодического регистра — период + все измерения. Две записи с одинаковым ключом в регистре быть не может: при записи платформа выдаст ошибку о том, что запись с такими ключевыми полями уже существует.
Режим записи
- 🔓 Независимый — записи вводит пользователь вручную или код через менеджер записи. Регистратора нет.
- 📄 Подчинение регистратору — записи создаёт документ при проведении и удаляет при отмене проведения.
Как читать последнее значение
Главный приём — виртуальная таблица СрезПоследних. Она возвращает для каждой комбинации измерений последнее значение на указанную дату. Её сестра СрезПервых даёт первое значение после даты.
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| Цены.Номенклатура,
| Цены.Цена
|ИЗ
| РегистрСведений.ЦеныНоменклатуры.СрезПоследних(&Дата, ВидЦены = &ВидЦены) КАК Цены";
Запрос.УстановитьПараметр("Дата", ТекущаяДатаСеанса());
Запрос.УстановитьПараметр("ВидЦены", ВидЦены);
Результат = Запрос.Выполнить().Выгрузить();
Если курс на 15-е число не вводили, а последняя запись — от 10-го, срез на 15-е вернёт значение от 10-го. Именно так в типовых решениях берутся курсы и цены «на дату документа».
Регистр накопления: остатки и обороты
Регистр накопления отвечает на вопрос «сколько». Сколько товара на складе, сколько продано за месяц, сколько должен контрагент. Он всегда подчинён регистратору: записи появляются только из документов.
Два вида регистров накопления
- 📦 Остатки. Каждая запись имеет
ВидДвижения—ПриходилиРасход. Платформа хранит итоги и умеет считать остаток на любой момент. Пример: остатки товаров на складах, взаиморасчёты. - 📈 Обороты. Вида движения нет, записи только суммируются. Остаток здесь не имеет смысла. Пример: продажи, выручка по менеджерам.
Выбор простой. Если вопрос «сколько сейчас осталось» имеет смысл — нужен регистр остатков. Если важна только сумма за период — регистра оборотов достаточно, и он легче.
Как платформа получает остаток
Остаток не пересчитывается из всех записей с начала времён. Платформа хранит итоги — накопленные значения ресурсов по измерениям на начало каждого месяца, плюс текущие итоги. Запрос остатка на 18 марта берёт итоги ближайшего месяца и досчитывает движения между этой точкой и датой запроса.
Пример: на 1 марта по складу «Основной» итог 120 шт. С 1 по 18 марта пришло 40 шт., ушло 55 шт. Остаток на 18 марта: 120 + 40 − 55 = 105 шт. Платформа прочитает одну строку итогов и движения за 18 дней, а не всю историю.
Пример проведения расходного документа
Процедура ОбработкаПроведения(Отказ, Режим)
Движения.ОстаткиТоваров.Записывать = Истина;
Для Каждого СтрокаТЧ Из Товары Цикл
Движение = Движения.ОстаткиТоваров.Добавить();
Движение.ВидДвижения = ВидДвиженияНакопления.Расход;
Движение.Период = Дата;
Движение.Склад = Склад;
Движение.Номенклатура = СтрокаТЧ.Номенклатура;
Движение.Количество = СтрокаТЧ.Количество;
КонецЦикла;
КонецПроцедуры
Флаг Записывать = Истина говорит платформе: после выхода из обработчика этот набор надо записать в базу. Без флага движения не сохранятся, и документ будет проведён «вхолостую».
Регистр бухгалтерии: двойная запись по плану счетов
Регистр бухгалтерии хранит проводки. Он всегда связан с планом счетов, а аналитика по счетам (субконто) берётся из плана видов характеристик. В 1С:Бухгалтерии 3.0 это регистр Хозрасчетный и одноимённый план счетов
.
Чем он отличается от регистра накопления
- 🔁 Корреспонденция. Если у регистра включено свойство «Корреспонденция», одна запись содержит и дебет, и кредит:
СчетДт,СчетКт,СубконтоДт,СубконтоКт, сумма. Это и есть проводка Дт — Кт. - 🧾 Субконто. Аналитика задаётся не жёсткими измерениями, а видами субконто, которые настроены на каждом счёте. На счёте 41 — номенклатура и склад, на счёте 60 — контрагент и договор.
- ⚖️ Балансовые признаки. Измерение или ресурс может быть балансовым (считается по Дт и Кт с проверкой равенства) или забалансовым.
- 📊 Итоги по счетам. Платформа хранит итоги не только по субконто, но и по самим счетам с учётом иерархии плана: остаток по счёту 60 складывается из субсчетов 60.01, 60.02 и т.д.
Пример записи проводки
Движения.Хозрасчетный.Записывать = Истина;
Проводка = Движения.Хозрасчетный.Добавить();
Проводка.Период = Дата;
Проводка.Организация = Организация;
Проводка.СчетДт = ПланыСчетов.Хозрасчетный.ТоварыНаСкладах;
Проводка.СчетКт = ПланыСчетов.Хозрасчетный.РасчетыСПоставщиками;
Проводка.Сумма = СуммаБезНДС;
Проводка.Содержание = "Поступление товаров";
Субконто заполняют через свойства СубконтоДт и СубконтоКт — это коллекции, где ключ — вид субконто. В типовых конфигурациях для этого есть служебные процедуры, писать вручную каждую строку не приходится.
Отчёты «Оборотно-сальдовая ведомость», «Карточка счёта», «Анализ счёта» в 1С:Бухгалтерии читают именно этот регистр через его виртуальные таблицы.
Проведение документа: как движения попадают в регистры
Порядок событий при проведении один для всех регистров.
- Пользователь нажимает «Провести». Платформа открывает транзакцию.
- Документ записывается в базу, затем вызывается обработчик
ОбработкаПроведения(Отказ, Режим)в модуле объекта. - В обработчике код заполняет коллекцию
Движения: по набору записей на каждый регистр, где установлен флагЗаписывать. - После выхода из обработчика платформа записывает наборы: удаляет старые движения документа и пишет новые, обновляет итоги.
- Если где-то установлен
Отказ = Истинаили возникло исключение, транзакция откатывается целиком. Документ остаётся в прежнем состоянии.
Оперативное и неоперативное проведение
Параметр Режим принимает значения РежимПроведенияДокумента.Оперативный или Неоперативный. Оперативное проведение — это документ текущей датой, когда важно проверить реальный остаток «здесь и сейчас». Неоперативное — задним числом, проверки упрощаются.
Контроль остатков и блокировки
В современных конфигурациях с управляемыми блокировками остаток проверяют так:
- Установить управляемую блокировку
БлокировкаДанныхна нужные записи регистра (склад + номенклатура). - Записать движения.
- Выполнить запрос к виртуальной таблице
Остаткии найти отрицательные значения. - Если они есть — сообщить пользователю и установить
Отказ = Истина.
Блокировка не даёт двум пользователям одновременно списать один и тот же последний товар. Без неё оба документа увидят остаток 5 шт. и оба спишут по 5.
Виртуальные таблицы и итоги: почему отчёты работают быстро
Читать регистр «в лоб» из основной таблицы — значит перебирать все записи. Для этого платформа даёт виртуальные таблицы. Это не таблицы в базе, а готовые запросы к итогам и движениям.
| Регистр | Виртуальные таблицы |
|---|---|
| Сведений (периодический) | СрезПоследних, СрезПервых |
| Накопления, остатки | Остатки, Обороты, ОстаткиИОбороты |
| Накопления, обороты | Обороты |
| Бухгалтерии | Остатки, Обороты, ОстаткиИОбороты, ОборотыДтКт, ДвиженияССубконто |
Условие — в параметры, а не в ГДЕ
Главное правило оптимизации: отбор по измерениям передавайте в параметры виртуальной таблицы.
// Правильно: отбор внутри параметров
ИЗ РегистрНакопления.ОстаткиТоваров.Остатки(&Момент, Склад = &Склад) КАК Ост
// Медленно: сначала считаются остатки по всем складам, потом отбрасываются лишние
ИЗ РегистрНакопления.ОстаткиТоваров.Остатки(&Момент) КАК Ост
ГДЕ Ост.Склад = &Склад
На базе с 200 складами разница — в 200 раз меньше данных на этапе расчёта итогов.
Момент времени и граница
Если передать в Остатки просто дату документа, остаток считается на начало этой секунды. Движения других документов той же секунды могут попасть или не попасть в расчёт. Чтобы получить остаток ровно до текущего документа, передают Новый Граница(МоментВремени(), ВидГраницы.Исключая).
Настройки итогов
- ⚙️ Использование итогов. Если их выключить (например, на время загрузки большого объёма данных), запросы остатков станут очень медленными. После загрузки итоги включают и пересчитывают.
- 🔀 Разделение итогов. Свойство регистра «Разрешить разделение итогов» снижает конфликты блокировок при массовой одновременной записи. Платформа пишет итоги в несколько строк-разделителей, а при чтении складывает их.
- 🧮 Агрегаты. Только у регистров оборотов. Это заранее посчитанные срезы по части измерений и периодам. Включаются и перестраиваются через обработку «Управление итогами».
💡 Обработка «Управление итогами» есть в любой конфигурации: включите в настройках отображение меню «Все функции» и откройте Все функции → Стандартные → Управление итогами. Там же — пересчёт итогов, установка периода рассчитанных итогов и управление агрегатами.
Ошибки при работе с регистрами и как их найти
Большинство проблем с регистрами видны пользователю как «неправильный остаток» или «документ не проводится». Причины обычно одни и те же.
Чего не делать
- ❌ Не отбирайте по реквизитам регистра в больших запросах — индекса по ним нет, если его не включили явно.
- ❌ Не обращайтесь из кода к физической таблице регистра там, где нужна виртуальная. На базе с миллионом движений запрос остатков «по записям» займёт минуты.
- ❌ Не правьте движения руками через «Ручную корректировку» без фиксации причины. Документ с ручной корректировкой больше не формирует движения автоматически: если потом поменять в нём сумму, проводки останутся старыми.
Пересчёт итогов и «Тестирование и исправление» запускайте после резервной копии и вне рабочего времени. «Тестирование и исправление» требует монопольного доступа: все пользователи должны выйти из базы. Пересчёт итогов на большой базе нагружает сервер и тормозит работу остальных сеансов.