Иногда возникают ситуации, когда стандартное удаление объектов через интерфейс 1С или программный метод Удалить() не подходит. Чаще всего это связано с экстремально большими объемами данных, например, при свертке базы за много лет или при необходимости полной очистки данных по одной организации в огромной базе. В подобных сценариях часто применяется универсальная очистка базы и удаление документов по организации. В таких случаях программисты прибегают к «хирургическому» вмешательству — удалению данных напрямую средствами SQL. Разберем подробно, как реализовать этот процесс, не превратив базу в набор «битых» ссылок.
Прежде чем приступать к удалению, нам необходимо выяснить, в каких именно таблицах SQL Server лежат данные нужных нам документов. В 1С имена таблиц в СУБД (например, _Document150) не совпадают с именами объектов в конфигураторе. Проанализируем, как получить эти соответствия и выполнить сопоставление объектов метаданных 1С и таблиц SQL Server. Мы не будем гадать или искать таблицы вручную — для этого в платформе 1С предусмотрен штатный механизм. Чтобы упростить эту задачу, можно использовать готовую обработку, описывающую структуру хранения базы данных.
Воспользуемся методом ПолучитьСтруктуруХраненияБазыДанных(). Этот метод возвращает таблицу значений, в которой указаны имена таблиц SQL для самого документа, его табличных частей, движений по регистрам и даже таблиц регистрации изменений для планов обмена. Рассмотрим пример кода, который поможет нам собрать информацию о «целях» для удаления:
ИменаМетаданных = Новый Массив;
ИменаМетаданных.Добавить("Документ.РеализацияТоваровУслуг");
Структура = ПолучитьСтруктуруХраненияБазыДанных(ИменаМетаданных, Истина);
Для Каждого СтрокаСтруктуры Из Структура Цикл
// Здесь мы получаем ИмяТаблицыХранения (SQL-имя)
// и Назначение (Основная, ТабличнаяЧасть, Движения и т.д.)
Сообщить("Объект: " + СтрокаСтруктуры.ИмяТаблицы + " -> SQL: " + СтрокаСтруктуры.ИмяТаблицыХранения);
КонецЦикла;
Одной из главных сложностей при работе с SQL напрямую является формат хранения ссылок. В 1С идентификатор binary(16) хранится в специфическом виде. Если мы просто возьмем UUID из 1С, он не совпадет с тем, что мы увидим в колонке _IDRRef в SQL без преобразования, учитывающего все особенности работы с уникальными идентификаторами (GUID) в прямых SQL-запросах. Понимание этих нюансов необходимо, когда мы анализируем SQL сервер глазами 1С-ника для поиска проблемных записей.
Разберем ситуацию: для удаления строк из табличных частей (например, _Document150_VT152), нам нужно знать _DocumentIDRRef, который соответствует _IDRRef из основной таблицы документа. Выясним, как преобразовать ссылку 1С в HEX-строку, которую поймет SQL Server. Посмотрим на пример функции для формирования бинарного представления:
// Пример преобразования идентификатора для использования в SQL запросе
Функция ПолучитьHexСсылку(Ссылка)
Идентификатор = Ссылка.УникальныйИдентификатор();
Стр = СтрЗаменить(Строка(Идентификатор), "-", "");
// В SQL 1С байты GUID перевернуты особым образом
// Для простоты формирования запроса через ADO можно использовать HEX-константу
Возврат "0x" + Сред(Стр, 25, 8) + Сред(Стр, 21, 4) + Сред(Стр, 17, 4) + Сред(Стр, 1, 16);
КонецФункции
Важный момент: Современные версии SQL Server позволяют передавать параметры в запросы напрямую через ADO в бинарном виде, что избавляет от необходимости вручную переворачивать байты. Однако понимание структуры HEX-строки критично при отладке запросов в SQL Management Studio.
Проанализируем правильную последовательность действий. Нельзя просто удалить запись из таблицы документа. Если мы удалим «шапку», а выполнение скрипта прервется, в базе останутся «сироты» в табличных частях и движениях, которые потом будет крайне сложно найти и вычистить. Рассмотрим правильный алгоритм действий, направленный на обеспечение ссылочной целостности при прямом удалении данных из 1С:
_ChngR). Если этого не сделать, механизмы синхронизации будут пытаться отправить в другие базы данные об объекте, которого уже нет._DocumentN_VT_M, где _DocumentIDRRef совпадает с идентификатором документа._DocumentN.Чтобы гарантировать целостность данных, все операции удаления должны выполняться внутри блока BEGIN TRANSACTION. Это обеспечит принцип «все или ничего»: если при удалении хотя бы одной строки возникнет ошибка (например, из-за блокировки), SQL Server откатит все изменения назад к исходному состоянию.
Рассмотрим структуру SQL-скрипта, который мы можем сформировать в 1С и отправить на исполнение через ADODB.Connection:
BEGIN TRANSACTION;
BEGIN TRY
-- Удаляем движения по регистру накопления
DELETE FROM _AccumReg120 WHERE _RecorderRRef = @DocRef;
-- Удаляем табличные части
DELETE FROM _Document150_VT152 WHERE _DocumentIDRRef = @DocRef;
-- Удаляем сам документ
DELETE FROM _Document150 WHERE _IDRRef = @DocRef;
COMMIT TRANSACTION;
END TRY
BEGIN CATCH
ROLLBACK TRANSACTION;
-- Здесь можно получить описание ошибки через ERROR_MESSAGE()
END CATCH;
Самая большая «подводная камнь» при удалении через SQL — это итоги регистров. В 1С таблицы итогов (_AccumRegTotals) хранят рассчитанные остатки на начало каждого месяца. При прямом удалении движений из основной таблицы регистра SQL Server не пересчитывает итоги автоматически, так как логика расчета находится на стороне сервера приложений 1С.
Выясним, что нужно сделать после завершения SQL-операций. Обязательно необходимо выполнить пересчет итогов в 1С:Предприятие после манипуляций на уровне SQL. Это можно сделать через Конфигуратор или программно. Без этой процедуры отчеты будут показывать старые остатки, несмотря на отсутствие записей в базе.
Также проанализируем ситуацию с составными типами данных. Если ссылка на удаляемый документ хранится в реквизите другого объекта, то после удаления эти поля в других таблицах станут указывать на несуществующий объект. Это приведет к появлению надписей «Объект не найден». В таких ситуациях крайне полезным оказывается универсальное удаление движений по битым ссылкам, которое позволяет вычистить проблемные записи без долгого тестирования и исправления всей базы.
При массовом удалении (миллионы строк) файл лога транзакций (.ldf) может вырасти до гигантских размеров. Разберем, как этого избежать, выполнив грамотную настройку лога транзакций и модели восстановления при массовых операциях:
Full, после удаления огромного объема данных стоит сделать бэкап лога или временно переключить базу в модель Simple.Подведем итог: удаление через SQL — это мощный инструмент, который требует от программиста четкого понимания структуры базы данных _IDRRef, _TRef и связей между таблицами. Используйте этот метод только тогда, когда стандартные средства 1С не справляются с объемом задачи, и всегда делайте резервную копию базы перед началом работ.