При работе с высоконагруженными базами данных 1С 8.3 стандартные механизмы удаления объектов (через встроенный язык и метод Удалить()) могут работать крайне медленно, особенно когда речь идет о свертке базы за несколько лет (поможет ускоренная свертка документов 1С через прямые SQL-запросы). В таких случаях администраторы и разработчики прибегают к прямому удалению данных средствами СУБД MS SQL Server. Однако архитектура 1С 8.3 значительно сложнее старых версий (7.7 или 8.1), и простое удаление строк может привести к фатальному повреждению логической целостности базы.
В этой статье мы подробно разберем, как правильно составить SQL-запросы для удаления документов и их движений, учитывая специфику хранения дат, типизацию идентификаторов и структуру таблиц в актуальной платформе 1С. Для этой задачи есть набор обработок для очистки документов и сжатия базы.
Прежде чем приступать к выполнению деструктивных запросов, нам необходимо понять, как 1С преобразует свои объекты метаданных в таблицы SQL (поможет инструмент анализа физической структуры базы 1С). В отличие от версии 7.7, где имена таблиц были фиксированными (например, _1SJOURN), в 1С 8.3 имена генерируются динамически (например, _Document125, _AccumReg150).
Для определения соответствия между именами в конфигураторе и именами в SQL проанализируем метод ПолучитьСтруктуруХраненияБазыДанных(). Этот метод позволяет получить таблицу, где указаны имена всех физических таблиц и их полей. Основные правила связи, которые нам пригодятся:
_IDRRef (для документов) и имеют тип binary(16)._RecorderRRef. Именно по этому полю происходит связь регистра с регистратором._DocumentJournal...). Если их не очистить, в интерфейсе 1С останутся "битые" ссылки (фантомные записи).Проанализируем важную техническую особенность 1С: хранение дат. При создании базы в 1С часто выбирается опция "Смещение дат - 2000". Это делается для того, чтобы избежать проблем с минимальными значениями дат в SQL Server.
Если смещение установлено, то дата 01.01.2022 в таблицах SQL будет выглядеть как 4022-01-01. Чтобы проверить текущее смещение в вашей базе, выполним следующий запрос:
SELECT [_YearOffset] FROM [_YearOffset]
При написании запросов на удаление по периоду мы должны обязательно прибавлять это смещение к искомой дате, иначе SQL-запрос отработает впустую, не найдя ни одной записи.
Рассмотрим ситуацию: нам нужно удалить все документы определенного типа и все их записи во всех регистрах. Вместо того чтобы вручную перечислять десятки таблиц регистров, воспользуемся системными представлениями MS SQL для автоматического поиска.
В 1С 8.3 поле, указывающее на документ-основание в регистрах, всегда называется _RecorderRRef. Мы можем составить список всех таблиц базы данных, в которых есть эта колонка:
SELECT t.name
FROM sys.columns c
JOIN sys.tables t ON c.object_id = t.object_id
WHERE c.name = '_RecorderRRef'
Это позволит нам построить универсальный цикл (курсор) для очистки всех движений, связанных с удаляемыми документами.
Разберем по шагам логику безопасного (насколько это возможно для SQL) удаления. Предположим, мы хотим удалить документы из таблицы _Document100 (имя таблицы нужно предварительно узнать через ПолучитьСтруктуруХраненияБазыДанных), период которых меньше 1 января 2022 года.
Важно: Все операции обязательно проводим внутри транзакции!
-- 1. Создаем временную таблицу с идентификаторами удаляемых документов
SELECT _IDRRef INTO #DocsToDelete
FROM _Document100
WHERE _Date_Time < '4022-01-01 00:00:00' -- Учитываем смещение +2000 лет
-- 2. Удаляем движения из всех регистров, где эти документы являются регистраторами
DECLARE @TableName NVARCHAR(128)
DECLARE @SQL NVARCHAR(MAX)
DECLARE TableCursor CURSOR FOR
SELECT t.name
FROM sys.columns c
JOIN sys.tables t ON c.object_id = t.object_id
WHERE c.name = '_RecorderRRef'
OPEN TableCursor
FETCH NEXT FROM TableCursor INTO @TableName
WHILE @@FETCH_STATUS = 0
BEGIN
SET @SQL = 'DELETE FROM ' + QUOTENAME(@TableName) + ' WHERE _RecorderRRef IN (SELECT _IDRRef FROM #DocsToDelete)'
EXEC sp_executesql @SQL
FETCH NEXT FROM TableCursor INTO @TableName
END
CLOSE TableCursor
DEALLOCATE TableCursor
-- 3. Удаляем сами записи документов
DELETE FROM _Document100 WHERE _IDRRef IN (SELECT _IDRRef FROM #DocsToDelete)
-- 4. Очищаем временную таблицу
DROP TABLE #DocsToDelete
Проанализируем ситуацию глубже. В 1С 8.3 документы регистрируются в журналах. Если вы удалили запись из _Document100, но не удалили её из _DocumentJournal..., пользователь все равно увидит строку в общем списке документов, но при попытке открытия получит ошибку "Объект не найден".
Также не забываем про планы обмена. Если ваша база участвует в репликации, необходимо очистить таблицы изменений _DocXXXX_ChngR. В противном случае система будет пытаться "выгрузить" удаленные документы, что приведет к ошибкам синхронизации.
После прямого выполнения DELETE в SQL база данных не уменьшится в размере автоматически, а логическая целостность итогов будет нарушена. Рассмотрим обязательные шаги по завершении процедуры:
_AccumRegTotals...). Необходимо зайти в Конфигуратор и запустить "Тестирование и исправление" с галочкой "Пересчет итогов" или воспользоваться консолью управления итогами в режиме "Предприятие".SHRINKDATABASE или SHRINKFILE через SQL Management Studio — для этого подойдёт универсальный инструмент для свертки и сжатия баз 1С.EXEC sp_updatestats.Прямое удаление данных через MS SQL — это крайняя мера. Помните о следующих рисках:
ПередУдалением и т.д.).Всегда выполняйте такие операции на копии базы данных и проверяйте результат с помощью встроенных отчетов 1С до того, как пускать пользователей в рабочую базу. В качестве безопасной альтернативы SQL-удалению можно использовать безопасное удаление данных с анализом ссылочной целостности.