При интеграции сторонних веб-сервисов или баз данных на MySQL с платформой 1С:Предприятие 7.7 стандартный перебор через ADODB.Recordset и поэлементная запись штатными объектами 1С вызывают катастрофическое падение производительности на больших объемах данных. Выясним причину этой проблемы и разберем эффективные подходы к ускорению переноса данных напрямую на уровне СУБД и средствами внешних компонент.
Когда мы построчно считываем данные через ADO и создаем объекты штатным языком 1С, на каждую запись выполняются десятки служебных операций: сетевые запросы, блокировки таблиц, проверка ссылочной целостности и пересчет служебных таблиц. В результате обработка сотен тысяч строк может занимать многие часы.
Рассмотрим основные варианты оптимизации переноса данных: от настройки транзакций до прямой пакетной вставки через Linked Server и расширение 1С++.
Если логика загрузки требует обязательного использования штатных методов 1С (например, когда создаются сложные документы с движениями или периодические реквизиты), необходимо минимизировать дисковые операции СУБД за счет группировки в транзакции.
Разберем по шагам, как организовать порционную запись:
Посмотрим на пример организации порционной записи:
Счетчик = 0;
РазмерПакета = 500;
НачатьТранзакцию();
Пока ВыборкаMySQL.EOF() = 0 Цикл
Счетчик = Счетчик + 1;
Спр = СоздатьОбъект("Справочник.Номенклатура");
// Заполнение реквизитов объекта
// ...
Спр.Записать();
Если Счетчик % РазмерПакета = 0 Тогда
ЗафиксироватьТранзакцию();
НачатьТранзакцию();
КонецЕсли;
ВыборкаMySQL.MoveNext();
КонецЦикла;
ЗафиксироватьТранзакцию();
Наиболее быстрое решение — исключить передачу данных через интерфейс 1С и выполнить перенос напрямую между базами данных на уровне MS SQL Server.
Проанализируем шаги настройки связанного сервера:
MSDASQL, указывая параметры подключения к MySQL.OPENQUERY. Это критически важно: OPENQUERY передает запрос на выполнение самому серверу MySQL, снижая нагрузку на сеть и MS SQL Server.Посмотрим на пример выборки данных через Linked Server:
SELECT *
FROM OPENQUERY(MYSQL_SERVER, 'SELECT id, article, name, price FROM products WHERE updated_at >= NOW() - INTERVAL 1 DAY');
При выполнении прямых операций INSERT или UPDATE в таблицы 1С:Предприятия 7.7 необходимо строго учитывать внутреннюю структуру хранения данных:
ID, IDDOC) представляют собой 9-символьные строки в 36-ричной системе счисления. Текущий максимальный идентификатор хранится в системной таблице 1SSYSTEM (поле CURRID). При прямой вставке новых записей обязательно нужно корректно обновлять счетчик в 1SSYSTEM, иначе возникнут дубликаты первичных ключей при штатной работе пользователей.SC***) обязательно заполняются поля ISMARK, ISFOLDER, PARENTEXT и системный ROW_ID.COLLATE.Самым надежным и быстрым подходом является двухэтапная схема (Staging):
ODBCRecordset читаем подготовленные данные прямым SQL-запросом и пакетно обновляем таблицы 1С с использованием метапарсера (макросов типа $Справочник.Номенклатура).Разберем пример пакетного обновления реквизитов через ODBCRecordset в 1С++:
ЗапросSQL = СоздатьОбъект("ODBCRecordset");
ТекстЗапроса = "
|UPDATE $Справочник.Номенклатура
|SET $Справочник.Номенклатура.Артикул = buf.article,
| $Справочник.Номенклатура.Цена = buf.price
|FROM $Справочник.Номенклатура AS nom
|INNER JOIN Buffer_MySQL_Products AS buf
| ON nom.CODE = buf.code
|WHERE nom.ISMARK = 0
|";
ЗапросSQL.Выполнить(ТекстЗапроса);
Использование связки из Linked Server, промежуточной таблицы и прямых запросов 1С++ позволяет сократить время синхронизации сотен тысяч записей с нескольких часов до нескольких секунд.