При разработке и тестировании сложных обработок в 1С программисты часто сталкиваются с задачей массового изменения данных. Это может быть кодирование элементов справочников, пересчет и заполнение регистров сведений или масштабная реструктуризация. Проводить такие тесты на рабочей базе крайне опасно, но даже на общей тестовой копии, где одновременно работают несколько разработчиков или аналитиков, восстанавливать всю базу из бэкапа (резервной копии) ради одной таблицы — неэффективно и неудобно.
В этой статье мы подробно разберем, как средствами MS SQL Server быстро создать резервную копию конкретных таблиц 1С и восстановить их в исходное состояние, не затрагивая работу остальных пользователей и не прибегая к полному восстановлению базы данных.
Представим ситуацию: наша обработка должна изменить два справочника и один регистр сведений. Нам необходимо иметь возможность многократно запускать отладку, каждый раз возвращая эти таблицы к исходному состоянию. Использовать стандартный механизм транзакций 1С для огромных массивов данных не всегда возможно из-за риска переполнения транзакционного лога СУБД и блокировок таблиц.
Напрямую работать с таблицами СУБД 1С нужно с особой осторожностью. Проанализируем основные риски и технические нюансы, которые нам предстоит учесть:
IDENTITY, которые нельзя перезаписать стандартным запросом INSERT без специальных флагов._Version (timestamp/rowversion) в СУБД изменяются автоматически. Нам нужно правильно обработать этот момент, чтобы не нарушить ссылочную целостность и логику объектной блокировки 1С.Разберем по шагам наиболее эффективные методы решения этой задачи.
Этот способ является наиболее простым и надежным для большинства повседневных задач разработчика. Он заключается в создании временной таблицы-дублера прямо внутри рабочей (или тестовой) базы данных и последующей перезаписи оригинальной таблицы.
Рассмотрим подробнее процесс создания копии. Для этого выполним запрос SELECT INTO. Выясним имя физической таблицы 1С в СУБД (например, с помощью функции ПолучитьСтруктуруХраненияБазыДанных() или обработки «Просмотр структуры базы данных»). Пусть наша таблица называется _Acc3322.
Выполним следующий скрипт для создания резервной копии:
-- Шаг 1: Проверяем существование старой копии и удаляем ее, если она есть
IF OBJECT_ID('_Acc3322_copy') IS NOT NULL
DROP TABLE _Acc3322_copy;
-- Шаг 2: Создаем копию таблицы вместе с данными
SELECT *
INTO _Acc3322_copy
FROM _Acc3322;
Важное предупреждение: команда SELECT INTO создает новую таблицу _Acc3322_copy и копирует в неё структуру столбцов и все записи. Однако она не переносит первичные ключи, индексы, внешние ключи и триггеры. Именно поэтому мы не можем просто удалить оригинал и переименовать копию — оригинальная таблица должна сохранить свою структуру со всеми индексами.
После проведения тестов и работы обработки нам необходимо вернуть данные обратно. Для этого мы очистим оригинальную таблицу с помощью быстрой операции TRUNCATE (которая сохраняет структуру и индексы, но мгновенно удаляет записи без записи каждой строки в лог транзакций) и выполним вставку данных обратно из нашей копии.
Разберем скрипт восстановления по шагам:
-- Разрешаем явную вставку значений в автоинкрементные поля (Identity)
SET IDENTITY_INSERT _Acc3322 ON;
BEGIN TRAN;
-- Быстро очищаем оригинальную таблицу, сохраняя ее структуру и индексы
TRUNCATE TABLE _Acc3322;
-- Выполняем вставку данных из копии
-- ВНИМАНИЕ: Нужно перечислить список всех полей таблицы явно!
INSERT INTO _Acc3322 (поле1, поле2, поле3, _Version)
SELECT поле1, поле2, поле3, _Version
FROM _Acc3322_copy;
COMMIT TRAN;
-- Возвращаем системную настройку в исходное состояние
SET IDENTITY_INSERT _Acc3322 OFF;
Проанализируем важный момент: использование конструкции SET IDENTITY_INSERT ON обязательно, если в таблице присутствует колонка с автоинкрементом. Без этого флага MS SQL Server выдаст ошибку при попытке выполнить команду INSERT.
Чтобы не заниматься ручным написанием списков полей и постоянным копированием скриптов в SQL Server Management Studio (SSMS), мы можем написать внешнюю обработку в 1С, которая будет программно формировать и выполнять эти скрипты.
Для реализации такой автоматизации нам потребуется использовать объект ADOConnection или класс УправлениеДоступом (в зависимости от настроек вашей системы). Посмотрим на пример алгоритма создания скрипта восстановления в модуле обработки 1С:
// Пример формирования списка полей для вставки, исключая системные ограничения
Функция ПолучитьСкриптВосстановления(ИмяТаблицыОригинала, ИмяТаблицыКопии) Экспорт
// Получаем структуру полей таблицы из системных представлений MS SQL
ЗапросSQL = "
|SELECT COLUMN_NAME
|FROM INFORMATION_SCHEMA.COLUMNS
|WHERE TABLE_NAME = '" + ИмяТаблицыОригинала + "'";
// Выполняем запрос к СУБД и собираем поля в строку
СписокПолей = "";
Пока ВыборкаПолей.Следующий() Цикл
// Исключаем системные поля, которые СУБД не разрешит записать напрямую,
// если они имеют специфический тип данных (например, rowversion без явного каста)
Если ВыборкаПолей.ИмяПоля = "_Version" Тогда
Продолжить; // Или обрабатываем отдельно
КонецЕсли;
СписокПолей = СписокПолей + "[" + ВыборкаПолей.ИмяПоля + "], ";
КонецЦикла;
// Удаляем лишнюю запятую в конце строки
СписокПолей = Лев(СписокПолей, СтрДлина(СписокПолей) - 2);
// Формируем результирующий пакетный запрос СУБД
ТекстСкрипта = "
|SET IDENTITY_INSERT " + ИмяТаблицыОригинала + " ON;
|BEGIN TRAN;
|TRUNCATE TABLE " + ИмяТаблицыОригинала + ";
|INSERT INTO " + ИмяТаблицыОригинала + " (" + СписокПолей + ")
|SELECT " + СписокПолей + " FROM " + ИмяТаблицыКопии + ";
|COMMIT TRAN;
|SET IDENTITY_INSERT " + ИмяТаблицыОригинала + " OFF;";
Возврат ТекстСкрипта;
КонецФункции
Запуск таких скриптов можно осуществлять по кнопке в нашей обработке 1С. Таким образом, весь цикл тестирования («создать копию» -> «запустить алгоритм» -> «откатить изменения») выполняется прямо из пользовательского интерфейса 1С.
Если вы работаете на редакции MS SQL Server Enterprise (или Standard, начиная с версии SQL Server 2016 SP1), существует альтернативный, гораздо более мощный способ решения задачи — использование моментальных снимков базы данных (Database Snapshots).
Вместо физического дублирования огромных таблиц внутри основной базы мы можем создать мгновенный снимок всей базы данных перед началом тестирования. Снимок создается практически моментально, так как использует технологию «копирования при записи» (copy-on-write) и изначально занимает 0 байт на диске.
Рассмотрим этот процесс по шагам:
CREATE DATABASE MyDatabase_Snapshot ON
( NAME = MyDatabase_Data, FILENAME = 'C:\SQLData\MyDatabase_Snapshot.ss' )
AS SNAPSHOT OF MyDatabase;
MyDatabase.
SET IDENTITY_INSERT MyDatabase.dbo._Acc3322 ON;
TRUNCATE TABLE MyDatabase.dbo._Acc3322;
INSERT INTO MyDatabase.dbo._Acc3322 (Поля)
SELECT Поля FROM MyDatabase_Snapshot.dbo._Acc3322;
SET IDENTITY_INSERT MyDatabase.dbo._Acc3322 OFF;
DROP DATABASE MyDatabase_Snapshot.Этот метод избавляет нас от необходимости плодить таблицы-копии внутри основной схемы данных СУБД 1С.
Обратим особое внимание на поле _Version. В СУБД под управлением 1С это поле имеет системный тип данных rowversion (или timestamp). Специфика этого типа заключается в том, что СУБД генерирует значение для этого столбца автоматически при добавлении или изменении записи.
Попытка прямой вставки сохраненных значений в колонку _Version может вызвать ошибку СУБД. В большинстве случаев для восстановления работоспособности данных 1С точные значения этого поля восстанавливать не требуется, так как платформа 1С использует его главным образом для контроля пессимистических блокировок. Однако, если вы восстанавливаете данные, новые значения версии строки гарантируют актуальность кэша СУБД, но могут вызвать ошибку «Объект изменен или удален другим пользователем» у тех клиентов 1С, кто держал эти объекты открытыми в форме во время вашей процедуры отката.
Помните: сервер приложений 1С ничего не знает о ваших манипуляциях на уровне MS SQL Server!
После того как вы выполнили TRUNCATE и вернули старые данные в таблицы, сервер 1С может продолжать отдавать пользователям закэшированные версии объектов из своей оперативной памяти. Это приведет к непредсказуемому поведению системы и ошибкам динамического обновления.
Поэтому сразу после восстановления таблиц выполните одно из следующих действий:
1C:Enterprise) или конкретный рабочий процесс rphost, обслуживающий тестируемую базу данных.Используя предложенные методики, мы можем безопасно и эффективно организовать изолированное тестирование сложных обработок в многопользовательской среде СУБД MS SQL.