Часто в процессе поддержки или разработки высоконагруженных баз данных 1С мы сталкиваемся с необходимостью выполнить универсальную очистку данных или полностью очистить огромный регистр сведений. Например, регистр соответствия объектов для обмена может содержать десятки миллионов записей. Проанализируем ситуацию: попытка очистить такой объем данных "в лоб", создав набор записей и записав его с пустым значением, неизбежно заканчивается ошибкой "Недостаточно памяти" (аналогичная проблема возникает при массовом удалении помеченных объектов).
Если попытаться удалить данные поэлементно в цикле, процесс может растянуться на долгие недели (до 40-45 суток). Выясним причину такого поведения платформы и детально разберем по шагам несколько эффективных способов решения этой нетривиальной задачи.
Ошибка "Недостаточно памяти" при записи пустого набора (или даже при попытке обычной реструктуризации) возникает из-за того, что платформа пытается обработать все миллионы записей разом, исчерпывая лимиты выделяемой оперативной памяти. Для 32-разрядных клиентов и рабочих процессов сервера 1С это ограничение составляет около 2 ГБ.
Кроме того, построчное удаление работает критически медленно из-за того, что каждая команда удаления создает отдельную неявную транзакцию в СУБД. Посмотрим на эффективные решения этой проблемы.
Если база данных работает в клиент-серверном варианте (MS SQL Server, PostgreSQL и др.), самым быстрым и эффективным методом будет очистка таблицы напрямую средствами СУБД. Разница в скорости колоссальна — очистка происходит практически мгновенно.
Разберем по шагам, как это сделать:
ПолучитьСтруктуруХраненияБазыДанных() или специализированными обработками._InfoRg7078.
TRUNCATE TABLE [ИмяВашейБазы].[dbo].[_InfoRg7078]
Важное примечание: Применение TRUNCATE TABLE удаляет данные минуя журнал транзакций построчно, что делает операцию сверхбыстрой и не ведет к сильной фрагментации индексов. Однако помните, что 1С не "знает" о прямом вмешательстве в СУБД. Этот метод рекомендуется использовать с осторожностью и обязательно после создания резервной копии.
Если очистку должен запускать конечный пользователь из режима Предприятия, мы можем настроить в СУБД Windows Authentication (авторизацию системой), создать отдельного пользователя с правами только на соединение и операцию DELETE/TRUNCATE для конкретной таблицы, и выполнять SQL-запрос напрямую из кода 1С через ADO.
Если прямое вмешательство в SQL невозможно, мы можем оптимизировать код 1С. Рассмотрим подробнее правильную структуру порционного удаления. Чтобы не переполнять память и не нагружать диск одиночными транзакциями, удалять данные нужно порциями (по 1000–5000 записей), оборачивая каждую порцию в транзакцию.
Посмотрим на пример оптимизированного кода:
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ ПЕРВЫЕ 1000
| СоответствиеОбъектовДляОбмена.УзелОбмена,
| СоответствиеОбъектовДляОбмена.СобственнаяСсылка,
| СоответствиеОбъектовДляОбмена.СсылкаВДругойИБ
|ИЗ
| РегистрСведений.СоответствиеОбъектовДляОбмена КАК СоответствиеОбъектовДляОбмена";
Пока Истина Цикл
Выборка = Запрос.Выполнить().Выбрать();
Если Выборка.Количество() = 0 Тогда
Прервать;
КонецЕсли;
НачатьТранзакцию();
Попытка
Пока Выборка.Следующий() Цикл
МЗ = РегистрыСведений.СоответствиеОбъектовДляОбмена.СоздатьМенеджерЗаписи();
МЗ.УзелОбмена = Выборка.УзелОбмена;
МЗ.СобственнаяСсылка = Выборка.СобственнаяСсылка;
МЗ.СсылкаВДругойИБ = Выборка.СсылкаВДругойИБ;
МЗ.Прочитать();
Если МЗ.Выбран() Тогда
МЗ.ОбменДанными.Загрузка = Истина; // Отключаем регистрацию на узлах обмена
МЗ.Удалить();
КонецЕсли;
КонецЦикла;
ЗафиксироватьТранзакцию();
Исключение
ОтменитьТранзакцию();
// Обработка ошибки (запись в ЖР и т.д.)
Прервать;
КонецПопытки;
КонецЦикла;
Ключевые моменты этого кода:
ПЕРВЫЕ 1000 дозирует нагрузку и спасает от разрывов соединения (ошибка 10054). Если база всё равно падает, уменьшите порцию до 500 или 100 записей.НачатьТранзакцию() и ЗафиксироватьТранзакцию() ускоряют процесс на порядки, так как СУБД сбрасывает данные на диск пакетом.ОбменДанными.Загрузка = Истина критически важна! Иначе платформа начнет регистрировать удаление каждого миллиона записей в таблицы регистрации обмена, что полностью заблокирует работу сети и раздует базу.Если в регистре не осталось ничего нужного, можно решить проблему инструментами разработчика. Однако банальное удаление регистра в конфигураторе и нажатие F7 приведет к всё той же ошибке нехватки памяти из-за попытки платформы удалить огромную таблицу в рамках одной транзакции реструктуризации.
Чтобы реструктуризация прошла успешно, разобьем процесс на три безопасных этапа:
В новых версиях платформы 1С (начиная с релизов 8.3.26 и 8.3.27) разработчики добавили новые, более умные алгоритмы записи наборов данных. К параметру РежимЗамещения были добавлены значения Удаление, Обновление и Слияние. Использование этих режимов позволяет платформе нативно формировать пакетные запросы для удаления данных, не перегружая кэш и оперативную память сервера.
Применяя комбинацию из этих методов, мы можем безопасно и быстро избавиться от миллионов лишних записей в базе данных, сохранив стабильность работы 1С-Предприятия.