Как в 1С 7.7 реализовать массовое удаление записей через прямые SQL-запросы к базе данных

Программист 1С v7.7 IT и автоматизация бизнеса
← На главную

При работе с высоконагруженными базами данных на платформе 1С 7.7 стандартные методы удаления объектов часто оказываются слишком медленными. Особенно это заметно при работе с системными таблицами, такими как _1SUPDTS (таблица регистрации изменений), где объем данных может исчисляться миллионами строк. В этой статье мы подробно разберем, как отойти от медленного удаления записей в цикле и перейти к эффективным прямым запросам к MS SQL Server, используя внешнюю компоненту 1С++.

Постановка задачи и анализ проблемы

Рассмотрим типичную ситуацию: программисту необходимо очистить таблицу от определенных записей, основываясь на значениях нескольких полей. В 1С 7.7 многие таблицы имеют составные первичные ключи (Primary Key). Например, в таблице регистрации изменений _1SUPDTS уникальность записи определяется комбинацией полей DBSIGN, TYPEID и OBJID.

Типичная, но неэффективная схема работы выглядит так:

  1. Выборка данных во временную ТаблицуЗначений.
  2. Обход таблицы в цикле Пока ... Цикл.
  3. Выполнение отдельного SQL-запроса на удаление (DELETE) для каждой строки.

Такой подход создает колоссальную нагрузку на сервер из-за постоянного открытия и закрытия транзакций, а также накладных расходов на передачу команд. Проанализируем, как можно ускорить этот процесс в десятки раз.

Особенности синтаксиса MS SQL Server для составных ключей

Часто разработчики, имеющие опыт работы с PostgreSQL или Oracle, пытаются применить конструкцию сравнения кортежей:

WHERE (U.OBJID, U.DBSIGN) IN (SELECT ...)

Важно помнить, что MS SQL Server не поддерживает такой синтаксис. При попытке выполнить подобный запрос вы получите ошибку о неверном типе данных или ожидаемом логическом выражении. Поэтому единственным верным и производительным способом для массовых операций с составными ключами в 1С 7.7 является использование временных таблиц и соединения INNER JOIN.

Шаг 1: Подготовка данных во временной таблице SQL

Для начала нам необходимо передать список идентификаторов, подлежащих удалению, из оперативной памяти 1С в SQL Server. Рассмотрим пример использования метода ВыполнитьSQL_ИзТЗ компоненты 1С++. Этот метод позволяет мгновенно наполнить физическую таблицу на сервере данными из 1С.

Создадим и подготовим временную таблицу:


// Создаем объект для работы с прямыми запросами
RS = СоздатьОбъект("ODBCRecordset"); 

// Определяем структуру временной таблицы в tempdb
// Используем тип Char(9) для идентификаторов 1С и Char(3) для кода базы
RS.ВыполнитьСкалярный("
      |IF OBJECT_ID('tempdb..#тбУдалять', 'U') IS NOT NULL
      |  DROP TABLE #тбУдалять;
      |CREATE TABLE #тбУдалять (OBJID Char(9), DBSIGN Char(3));");

// Подготавливаем инструкцию вставки
RS.Подготовить("
      |insert into #тбУдалять(OBJID, DBSIGN)
      |values(?, ?)");

// тбУдалять — это обычная ТаблицаЗначений в 1С с колонками OBJID и DBSIGN
RS.ВыполнитьSQL_ИзТЗ(тбУдалять);

Шаг 2: Массовое удаление через INNER JOIN

После того как данные загружены во временную таблицу #тбУдалять, мы можем выполнить операцию удаления одним запросом. Это позволяет SQL-серверу построить оптимальный план выполнения и обработать данные пакетом.

Разберем структуру эффективного запроса DELETE:


ТекстЗапроса = "
    |DELETE
    |    U
    |FROM
    |    _1SUPDTS as U          
    |INNER JOIN 
    |    #тбУдалять as T ON U.OBJID = T.OBJID AND U.DBSIGN = T.DBSIGN";

RS.ВыполнитьИнструкцию(ТекстЗапроса);

В данном примере мы используем алиас U для целевой таблицы. Обратите внимание на условие ON: мы связываем таблицы по всем полям, входящим в составной ключ. Это критически важно для производительности, так как позволяет серверу использовать существующие индексы основной таблицы.

Оптимизация и безопасность при больших объемах

Выясним, какие еще нюансы стоит учитывать при работе с прямыми запросами в 1С 7.7:

  1. Типы данных: Всегда следите за точным соответствием типов. Если поле в основной таблице имеет тип Char(9), то и во временной таблице оно должно быть Char(9). Использование Varchar может привести к неявному преобразованию типов (Implicit Conversion), из-за чего SQL Server проигнорирует индексы и выполнит полное сканирование таблицы (Table Scan).
  2. Лог транзакций: При удалении очень большого количества строк (например, более 100 000 за раз) лог транзакций (LDF-файл) может резко вырасти. Если вы столкнулись с такой проблемой, рекомендуется выполнять удаление порциями (пакетами) в цикле SQL.
  3. Блокировки: Прямое удаление через DELETE накладывает блокировки на строки или всю таблицу. Старайтесь выполнять такие операции в периоды минимальной активности пользователей.

Комплексный пример реализации

Проанализируем итоговый код, который объединяет выборку условий и последующее удаление. Предположим, нам нужно удалить регистрации изменений для документов, которые не соответствуют определенному складу.


// 1. Формируем ТЗ с данными для анализа в 1С
// ... (заполнение тбОбмен данными из запроса) ...

тбУдалять = СоздатьОбъект("ТаблицаЗначений");
тбУдалять.НоваяКолонка("OBJID");
тбУдалять.НоваяКолонка("DBSIGN");

тбОбмен.ВыбратьСтроки();
Пока тбОбмен.ПолучитьСтроку() = 1 Цикл         
    Если НужноУдалить(тбОбмен.Док, тбОбмен.Склад) = 1 Тогда
        тбУдалять.НоваяСтрока();
        тбУдалять.OBJID = тбОбмен.OBJID;
        тбУдалять.DBSIGN = тбОбмен.DBSIGN;
    КонецЕсли;
КонецЦикла;

// 2. Передаем ТЗ в SQL и удаляем
RS = СоздатьОбъект("ODBCRecordset");
RS.Выполнить("IF OBJECT_ID('tempdb..#тбУдалять', 'U') IS NOT NULL DROP TABLE #тбУдалять;");
RS.Выполнить("CREATE TABLE #тбУдалять (OBJID Char(9), DBSIGN Char(3));");

RS.Подготовить("INSERT INTO #тбУдалять (OBJID, DBSIGN) VALUES (?, ?);");
RS.ВыполнитьSQL_ИзТЗ(тбУдалять);

ТекстЗапроса = "
    |DELETE _1SUPDTS
    |FROM _1SUPDTS AS U
    |INNER JOIN #тбУдалять AS T ON U.OBJID = T.OBJID AND U.DBSIGN = T.DBSIGN";

RS.ВыполнитьИнструкцию(ТекстЗапроса);
Сообщить("Очистка завершена успешно!");

Использование этого метода позволяет сократить время выполнения операций с нескольких часов до нескольких минут, что является критически важным фактором при обслуживании крупных баз данных на платформе 1С 7.7.

← На главную