Работа с большими объемами данных в платформе 1С:Предприятие часто преподносит неприятные сюрпризы. Типичная ситуация: при попытке экспортировать справочник контрагентов объемом более 1,3 миллиона записей в формате XML на 32-разрядном клиенте система мгновенно выдает ошибку "Нехватка памяти", а на 64-разрядном — просто зависает без каких-либо сообщений. Попытки разбить выгрузку на мелкие части (даже за один день) или сменить обработку не дают результата.
В этой статье мы подробно разберем, почему возникают эти проблемы на системном уровне, проанализируем неочевидные симптомы повреждения базы данных и рассмотрим пошаговые методы оптимизации выгрузки больших массивов информации.
Для начала проанализируем поведение операционной системы и платформы 1С при обработке гигантских массивов данных:
Program Files (x86)), лимит увеличивается лишь до 4 ГБ, после чего программа точно так же падает. Если же запускается полноценный 64-разрядный клиент, лимита памяти нет, но процесс зависает. Это происходит из-за 100%-й загрузки процессора механизмами сборки мусора (Garbage Collector) платформы 1С и утечки памяти в циклах преобразования объектов в XML-структуру.Если в базе данных наблюдаются проблемы с удалением помеченных на удаление объектов, это напрямую указывает на две критические системные проблемы:
Во-первых, налицо **логическое или физическое повреждение файлов базы данных** (в файловом режиме работы — файла 1Cv8.1CD). При нарушении индексов или целостности таблиц стандартные SQL-подобные выборки данных начинают зацикливаться.
Во-вторых, виной всему **блокировка памяти при контроле ссылочной целостности**. Платформа 1С, перед тем как удалить помеченные элементы, строит в оперативной памяти полную карту связей для всех 1,3 миллиона контрагентов. Файловая СУБД на таком объеме данных просто захлебывается и уходит в бесконечный цикл расчетов.
Часто выгрузка по частям не работает из-за логических ошибок в самих данных. Яркий пример — рекурсивная связь. Если в справочнике Контрагенты поле ГоловнойКонтрагент ссылается на этого же самого контрагента (или существует циклическая зависимость между несколькими контрагентами), стандартные рекурсивные алгоритмы построения дерева XML уходят в бесконечный цикл. Система бесконечно генерирует вложенные узлы, пока не закончится память.
Для выявления таких циклических ссылок выполним следующий запрос:
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| Контрагенты.Ссылка КАК Ссылка,
| Контрагенты.Представление КАК Представление
|ИЗ
| Справочник.Контрагенты КАК Контрагенты
|ГДЕ
| Контрагенты.ГоловнойКонтрагент = Контрагенты.Ссылка";
Результат = Запрос.Выполнить();
Если Не Результат.Пустой() Тогда
Выборка = Результат.Выбрать();
Пока Выборка.Следующий() Цикл
Сообщить("Обнаружена циклическая ссылка в элементе: " + Выборка.Представление);
КонецЦикла;
КонецЕсли;
---
Рассмотрим последовательность действий, которая позволит гарантированно выгрузить справочник любого объема даже на обычном офисном компьютере.
Прежде чем приступать к программированию или настройке выгрузки, необходимо вылечить файловую структуру информационной базы:
C:\Program Files\1cv8\номер_версии\bin\) и запустите утилиту chdbfl.exe. Обязательно укажите путь к файлу базы данных 1Cv8.1CD (предварительно сделав резервную копию!). Поставьте галочку "Исправлять обнаруженные ошибки" и запустите проверку. Она восстановит физическую целостность таблиц и индексов..dt. Затем создайте на диске новую пустую папку, добавьте ее в список информационных баз и загрузите туда данные из файла .dt. Этот процесс полностью пересоздает структуру файлов базы данных, избавляя ее от фрагментации.Убедимся, что операционная система дает платформе 1С использовать доступные ресурсы компьютера:
C:\Program Files\1cv8\..., а не C:\Program Files (x86)\1cv8\.... Это позволит процессу использовать всю доступную оперативную память ПК (например, все 8 ГБ).bcdedit /set increaseuserva 3072
Основная ошибка стандартных обработок (например, УниверсальныйОбменДаннымиXML) заключается в том, что по умолчанию они выгружают данные внутри одной огромной транзакции или пытаются построить дерево объектов в памяти перед записью на диск.
Проанализируем правила безопасной выгрузки больших объемов данных:
ЗаписьXML.Рассмотрим пример правильной потоковой выгрузки справочника порциями (пейджинг) с автоматическим освобождением памяти:
// Создаем объект потоковой записи файла на диск
ЗаписьXML = Новый ЗаписьXML;
ЗаписьXML.ОткрытьФайл("C:\Temp\Export_Counterparties.xml", "UTF-8");
ЗаписьXML.ЗаписатьОбъявлениеXML();
ЗаписьXML.ЗаписатьНачалоЭлемента("ДанныеСправочника");
// Настраиваем порционную выборку данных (выгружаем пачками по 10 000 элементов)
РазмерПорции = 10000;
ПоследнийКод = "";
Пока Истина Цикл
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ ПЕРВЫЕ " + Формат(РазмерПорции, "ЧГ=0") + "
| Контрагенты.Ссылка КАК Ссылка,
| Контрагенты.Код КАК Код,
| Контрагенты.Наименование КАК Наименование,
| Контрагенты.ИНН КАК ИНН
|ИЗ
| Справочник.Контрагенты КАК Контрагенты
|ГДЕ
| Контрагенты.Код > &ПоследнийКод
|УПОРЯДОЧИТЬ ПО
| Код";
Запрос.УстановитьПараметр("ПоследнийКод", ПоследнийКод);
РезультатЗапроса = Запрос.Выполнить();
Если РезультатЗапроса.Пустой() Тогда
Прервать; // Все данные успешно выгружены
КонецЕсли;
Выборка = РезультатЗапроса.Выбрать();
Пока Выборка.Следующий() Цикл
// Записываем каждый элемент последовательно, не перегружая ОЗУ
ЗаписьXML.ЗаписатьНачалоЭлемента("Контрагент");
ЗаписьXML.ЗаписатьАтрибут("Код", Выборка.Код);
ЗаписьXML.ЗаписатьАтрибут("Наименование", Выборка.Наименование);
ЗаписьXML.ЗаписатьАтрибут("ИНН", СокрЛП(Выборка.ИНН));
ЗаписьXML.ЗаписатьКонецЭлемента(); // Контрагент
ПоследнийКод = Выборка.Код;
КонецЦикла;
// Освобождаем память, принудительно вызывая очистку неиспользуемых ссылок платформой
СборкаМусора();
КонецЦикла;
ЗаписьXML.ЗаписатьКонецЭлемента(); // ДанныеСправочника
ЗаписьXML.Закрыть();
Сообщить("Выгрузка успешно завершена!");
Если файловая база данных все равно отказывается обрабатывать такой объем информации на локальном ПК, наиболее надежным решением станет перенос базы в клиент-серверный режим (SQL):
.dt в SQL-информационную базу.