При работе с высоконагруженными базами данных на платформе 1С:Предприятие 8 часто возникает задача удаления огромного количества записей. Например, регистр сведений ВерсииОбъектов может раздуваться до десятков миллионов строк, что делает стандартное удаление через интерфейс или стандартные обработки неэффективным. В этой статье мы подробно разберем, как очищать данные быстро, не вызывая блокировок и обходя типичные заблуждения о работе сервера 1С.
Рассмотрим ситуацию, с которой сталкиваются многие начинающие администраторы: после удаления данных напрямую в SQL Management Studio данные чудесным образом «возвращаются» в 1С. Выясним причину этого явления. Сервер приложений 1С активно использует кеширование объектов и записей в оперативной памяти. Если вы выполняете команду DELETE или TRUNCATE на уровне СУБД, сервер 1С не получает об этом уведомления. Он продолжает хранить старые значения в своем кеше и выдает их пользователю при запросе.
Важно понимать: никакого автоматического «отката» со стороны 1С не существует. Платформа не следит за состоянием таблиц SQL в реальном времени. Чтобы изменения вступили в силу и стали видны в интерфейсе, необходимо либо перезапустить службу сервера 1С, либо программно сбросить кеш, либо дождаться его естественного обновления. Для чистоты эксперимента при работе с прямыми запросами рекомендуется выполнять операции в технологическое окно, когда активные сеансы пользователей завершены.
Прежде чем переходить к прямым запросам, проанализируем самый быстрый штатный метод 1С. Вместо того чтобы перебирать записи в цикле и удалять их по одной (что крайне медленно), мы можем использовать механизм замещения набора записей.
Разберем пример кода для полной очистки регистра сведений: если же перед вами стоит задача очистить базу от данных только конкретной компании, для этого можно применить обработку для выборочного удаления организаций.
// Создаем пустой набор записей для регистра
Набор = РегистрыСведений.ВерсииОбъектов.СоздатьНаборЗаписей();
// Записываем его с параметром Замещать = Истина
// Платформа выполнит одну быструю транзакцию по удалению всех данных
Набор.Записать(Истина);
Этот метод работает значительно быстрее перебора, так как на уровне SQL формируется эффективный запрос. Однако для таблиц объемом в 10-20 миллионов записей даже этот способ может вызвать длительную блокировку таблицы и раздувание лога транзакций .LDF. В таких случаях мы переходим к инструментам СУБД.
Если нам нужно очистить таблицу полностью, самым эффективным инструментом в MS SQL Server является команда TRUNCATE TABLE. В отличие от DELETE, эта команда не записывает удаление каждой строки в лог транзакций, а просто освобождает страницы данных.
Проанализируем шаги для выполнения этой операции изнутри 1С через ADODB:
ПолучитьСтруктуруХраненияБазыДанных().
// Получаем имя таблицы SQL для нашего регистра
Структура = ПолучитьСтруктуруХраненияБазыДанных();
// Находим нужную таблицу по имени метаданных
ИмяТаблицыSQL = "";
Для Каждого СтрокаСтруктуры Из Структура Цикл
Если СтрокаСтруктуры.ИмяМетаданных = "РегистрСведений.ВерсииОбъектов" Тогда
ИмяТаблицыSQL = СтрокаСтруктуры.ИмяТаблицы;
Прервать;
КонецЕсли;
КонецЦикла;
Если ЗначениеЗаполнено(ИмяТаблицыSQL) Тогда
// Создаем COM-объект для связи с SQL
Connection = Новый COMОбъект("ADODB.Connection");
ConnectionString = "Provider=SQLOLEDB.1;Data Source=ИмяСервера;Initial Catalog=ИмяБазы;User ID=sa;Password=Пароль;";
Connection.Open(ConnectionString);
// Выполняем команду
Connection.Execute("TRUNCATE TABLE " + ИмяТаблицыSQL);
Connection.Close();
КонецЕсли;
Внимание: после выполнения TRUNCATE обязательно требуется очистить кеш сервера 1С, иначе вы будете видеть фантомные данные.
Если задача стоит очистить данные выборочно (например, удалить только старые версии объектов до определенной даты), использование TRUNCATE невозможно, а обычный DELETE может «повесить» базу. В этой ситуации мы применим пакетное удаление.
Рассмотрим логику запроса, который удаляет данные порциями по 50 000 записей. Это позволяет логу транзакций успевать очищаться и не блокирует таблицу намертво: при работе с 1С:ERP для подобных задач можно использовать обработку для многопоточной свёртки и очистки базы.
WHILE 1=1
BEGIN
DELETE TOP (50000) FROM _InfoRg12345 -- имя таблицы из структуры хранения
WHERE _Fld54321 < '2023-01-01' -- условие по дате
IF @@ROWCOUNT = 0 BREAK;
END
Такой подход позволяет выполнять очистку даже в рабочее время (при низком приоритете транзакций), так как между пакетами SQL Server может обрабатывать запросы других пользователей. При необходимости выборочной очистки без прямого доступа к СУБД можно использовать универсальную обработку для удаления и редактирования записей регистров сведений по фильтрам.
Иногда очистка требуется не по дате, а по факту наличия «битых» ссылок (объектов, которые были удалены, но записи в регистрах остались). В SQL ссылки хранятся в формате binary(16). Чтобы найти такие записи, нам нужно выполнить LEFT JOIN таблицы регистра с таблицей объекта (например, справочника).
Посмотрим на пример логики поиска битых ссылок в регистре сведений:
SELECT MainTable.*
FROM _InfoRg123 AS MainTable
LEFT JOIN _Reference45 AS RefTable ON MainTable._Fld678RRef = RefTable._IDRRef
WHERE RefTable._IDRRef IS NULL
Здесь _Fld678RRef — это поле ссылки в регистре, а _IDRRef — уникальный идентификатор в таблице справочника. Если в справочнике записи нет (результат NULL), значит, ссылка «битая» и её можно удалять.
Работа с базой данных напрямую через SQL — это мощный инструмент, требующий осторожности. Подведем итоги нашего исследования:
_InfoRg123) в код обработки. Используйте ПолучитьСтруктуруХраненияБазыДанных(), так как при обновлении конфигурации или реструктуризации номера таблиц могут измениться.Проанализировав все способы, мы видим, что для большинства задач очистки больших объемов данных оптимальным является сочетание пакетного DELETE через ADODB и последующего регламентного обслуживания базы штатными средствами 1С.