Случай с объединением таблиц
У одного из клиентов в отраслевой конфигурации, которая работает еще на платформе 8.3.9.2170 возникла ошибка, когда они пытались объединить данные за 12 месяцев в одну таблицу:
Объемы данных были большими, прежде чем ошибка была выдана, прошло 2 часа. Поэтому на отладку у меня было не очень много итераций, если конечно, не моделировать ситуацию на маленьких выборках.
К счастью, я сразу обнаружил узкое место в коде.
Дело в том, что каждая таблица из базы загружалась в таблицу значений в памяти, а потом объединялась в одну общую, объединенную таблицу:
ТЗ_РезультатОбъединения = МассивТЗДляОбъединения[0]; Для к = 1 по МассивТЗДляОбъединения.Количество()-1 Цикл ТЗ_РезультатОбъединения = СложитьТЗ(ТЗ_РезультатОбъединения,МассивТЗДляОбъединения[к]); КонецЦикла; ТЗ_РезультатОбъединения.ЗаполнитьЗначения(НоваяДатаЗагрузки,"ДатаЗагрузки");
А само сложение видимо в целях «быстродействия» делалось по заповедям 1С через виртуальные таблицы:
&НаСервере Функция СложитьТЗ(Таб1,Таб2) Запрос=Новый Запрос; МенеджерВременныхТаблиц = Новый МенеджерВременныхТаблиц; Запрос.МенеджерВременныхТаблиц = МенеджерВременныхТаблиц; Запрос.Текст = " |ВЫБРАТЬ * |ПОМЕСТИТЬ ВР_Таб1 |ИЗ | &Таб1 КАК Таб1" ; Запрос.УстановитьПараметр("Таб1",Таб1); Запрос.Выполнить(); Запрос=Новый Запрос; Запрос.МенеджерВременныхТаблиц = МенеджерВременныхТаблиц; Запрос.Текст = " |ВЫБРАТЬ * |ПОМЕСТИТЬ ВР_Таб2 |ИЗ | &Таб2 КАК Таб2" ; Запрос.УстановитьПараметр("Таб2",Таб2); Запрос.Выполнить(); ТекстЗапросаВыбораПолей = ""; Для Каждого Колонка из Таб1.Колонки Цикл ТекстЗапросаВыбораПолей = ТекстЗапросаВыбораПолей+"ВР_Табл1."+ Колонка.Имя+","; КонецЦикла; ТекстЗапросаВыбораПолей=Лев(ТекстЗапросаВыбораПолей,СтрДлина(ТекстЗапросаВыбораПолей)-1); Запрос = Новый Запрос; Запрос.Текст = "ВЫБРАТЬ " +ТекстЗапросаВыбораПолей+" |ИЗ | ВР_Таб1 КАК ВР_Табл1 | |ОБЪЕДИНИТЬ ВСЕ | |ВЫБРАТЬ " + СтрЗаменить(ТекстЗапросаВыбораПолей,"ВР_Табл1","ВР_Табл2")+" |ИЗ | ВР_Таб2 КАК ВР_Табл2"; Запрос.МенеджерВременныхТаблиц = МенеджерВременныхТаблиц; ТЗ= Запрос.Выполнить().Выгрузить(); Возврат ТЗ; КонецФункции
На этом 1С и валилась.
Самое удивительное, что я обнаружил, что дальнейший код обработки этой объединенной супер-таблицы можно переписать так, чтобы программа обращалась по очереди к каждой строке каждой из загруженной в память таблицы, т.е. объединять в одну таблицу нет смысла.
Кстати, в коде запись объединенной таблицы в базу данных была организована пачками по 1000 элементов, видимо, разработчики уже натыкались на ограничение, что большие наборы данных не записываются.
Закоментированный код — как было до, его заменяет мой новый код. Обратите внимание, как элегантно организован обход таблиц.
Мне повезло, что в каждой таблице были одинаковые колонки, иначе код обработки был бы сложнее.
//+++ не объединяем таблицы, заполняем колонку Для каждого ТЗКаждая ИЗ МассивТЗДляОбъединения Цикл ТЗКаждая.ЗаполнитьЗначения(НоваяДатаЗагрузки,"ДатаЗагрузки"); КонецЦикла; //--- //+++ Берем колонки из первой подходящей таблицы //КопияТЗ = ТЗ_РезультатОбъединения.СкопироватьКолонки(); // КопияТЗ = ТЗКаждая.СкопироватьКолонки(); //--- НомерПоПорядку = 0; КоличествоПачек = 0; //+++ Перебор каждой таблицы и каждой строки в ней //Для Сч = 0 По ТЗ_РезультатОбъединения.Количество()-1 Цикл Для каждого ТЗКаждая ИЗ МассивТЗДляОбъединения Цикл Для каждого ОбъединеннаяСтрока ИЗ ТЗКаждая Цикл //--- НоваяСтрока = КопияТЗ.Добавить(); //+++ тут другая строка используется //ЗаполнитьЗначенияСвойств(НоваяСтрока,ТЗ_РезультатОбъединения[Сч]); ЗаполнитьЗначенияСвойств(НоваяСтрока,ОбъединеннаяСтрока); //--- НомерПоПорядку = НомерПоПорядку + 1; Если НомерПоПорядку = 1000 Тогда КоличествоПачек = КоличествоПачек + 1; ... //Код сокращен, не имеет принципиального значения КопияТЗ.Очистить(); НомерПоПорядку = 0; КонецЕсли; КонецЦикла; //+++ тут два цикла вместо одного КонецЦикла; //---
Вот так вот иногда попытки оптимизировать приводят к проблемам производительности и масштабирования.
На мой взгляд, имело смысл сохранять каждую таблицу во временный регистр в базе данных, а не загромождать ими память. Но в принципе, с отдельными таблицами 1С еще справляется.
Объем: 1.5 час
Свежие комментарии