Как программно удалить все записи из регистра сведений в 1С?

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

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

Многие разработчики, знакомые с SQL, ищут аналог команды TRUNCATE TABLE или DELETE FROM TableName, чтобы удалить все данные одним запросом. Однако архитектура 1С устроена иначе. В этой статье мы подробно разберем, почему прямые запросы на удаление не работают в 1С так, как в SQL, и рассмотрим правильный, быстрый и безопасный способ очистки регистра сведений.

Почему нельзя просто выполнить запрос на удаление?

Сначала давайте разберемся с теоретической частью вопроса. В языке запросов 1С отсутствуют инструкции для модификации данных, такие как UPDATE, INSERT или DELETE. Язык запросов 1С предназначен исключительно для чтения данных.

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

Автор обсуждения задавался вопросом: нужно ли перебирать огромное количество записей в цикле и удалять их по одной? Ответ однозначный — нет. Удаление записей в цикле (получение выборки, удаление каждой записи через менеджер записи) — это крайне неэффективный процесс, который будет работать очень медленно на больших объемах данных.

Правильное решение: Использование Набора Записей

Самый быстрый и эффективный способ массового изменения данных в регистрах (как сведений, так и накопления/бухгалтерии) — это использование объекта НаборЗаписей. Давайте рассмотрим этот механизм подробнее.

Логика работы НаборЗаписей заключается в замещении. Когда мы записываем набор, система удаляет из базы данных все записи, которые соответствуют установленному отбору этого набора, и на их место помещает те записи, которые содержатся в самом объекте набора.

Отсюда вытекает элегантное решение для полной очистки регистра. Если мы создадим набор записей, не установим в нем никаких отборов (что равносильно охвату всей таблицы) и оставим его пустым, то при записи система удалит все старые записи и запишет "ничего".

Рассмотрим код, который решает эту задачу:


// Создаем объект НаборЗаписей для нужного регистра
НаборЗаписей = РегистрыСведений.МойРегистр.СоздатьНаборЗаписей();

// Не устанавливаем никаких отборов!
// По умолчанию набор пуст.

// Записываем пустой набор
НаборЗаписей.Записать();

Давайте проанализируем, что происходит в этих строках:

  1. РегистрыСведений.МойРегистр.СоздатьНаборЗаписей() — мы инициализируем объект для работы с коллекцией записей. В этот момент он пуст.
  2. Мы намеренно пропускаем шаг установки отбора (методы типа НаборЗаписей.Отбор.Измерение.Установить(...)). Отсутствие отбора означает, что набор "отвечает" за всю таблицу регистра целиком.
  3. НаборЗаписей.Записать() — платформа видит, что набор не ограничен фильтрами, и выполняет замену всех данных регистра на данные из памяти (то есть на пустоту).

Этот метод работает на порядки быстрее, чем построчное удаление, так как выполняется одной транзакцией и на уровне СУБД транслируется в оптимизированные команды удаления.

Важные нюансы и предостережения

Несмотря на простоту решения, необходимо учитывать несколько критически важных моментов, чтобы не нарушить работу базы данных.

1. Вид регистра: Независимый или Подчиненный регистратору

Описанный выше метод идеально подходит для независимых регистров сведений. Это регистры, записи в которых существуют сами по себе и не привязаны к конкретным документам.

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

2. Огромные объемы данных и транзакции

В обсуждении упоминалось "огромное количество записей". Если в вашем регистре содержатся миллионы строк, метод НаборЗаписей.Записать() без отборов может вызвать проблемы.

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

Если вы столкнулись с такой ситуацией (регистр слишком велик для очистки за один раз), рекомендуем удалять данные порциями. Например, устанавливая отбор по периоду или другому измерению:


// Пример порционной очистки (псевдокод)
ДатаНачала = Дата('20200101');
Пока ДатаНачала < ТекущаяДата() Цикл
    
    Набор = РегистрыСведений.МойРегистр.СоздатьНаборЗаписей();
    
    // Если регистр периодический, можно отбирать по периоду
    // Для непериодических нужно использовать другое измерение для порционирования
    // Здесь показан принцип идеи, а не универсальный код
    
    Набор.Отбор.Период.Установить(ДатаНачала, ДатаНачала + 30 * 86400); // Берем месяц
    Набор.Записать(); // Удаляем данные за этот месяц
    
    ДатаНачала = ДобавитьМесяц(ДатаНачала, 1);
КонецЦикла;

Однако для большинства стандартных задач (тысячи и десятки тысяч записей) простая запись пустого набора без отборов работает безупречно.

Заключение

Подведем итог нашему разбору. Чтобы удалить все данные из регистра сведений:

  1. Не пытайтесь использовать SQL-подобные запросы.
  2. Не используйте цикл с перебором и удалением каждой записи по отдельности.
  3. Используйте объект НаборЗаписей. Создайте его, не устанавливайте отборы и вызовите метод Записать().
  4. Убедитесь, что регистр является независимым, а объем данных не превышает критические лимиты вашей СУБД для одной транзакции.
← На главную