К сожалению какого-то конкретного материала по работе платформы с памятью не существует. Вопрос слишком абстрактный. Не могли бы Вы уточнить более конкретно, что Вас интересует?
Меня интересует, как заставить платформу более экономно расходовать память при подобных операциях.
У меня есть таблица, хранящая соответствие контрагентов и контактов в отношении многие-ко-многим. Мне нужно перенести ее содержимое в Terrasoft из внешней программы посредством COM. SQL-запросом я подготавливаю списки идентификаторов контрагентов и контактов и по одному записываю их в эту таблицу соответствий. При 5000 таких записей, Terrasoft забирает положенные ему 2 Гб памяти на 32-битной системе и падает с OutOfMemory.
Но когда я подобным образом дергаю контрагентов в источнике и записываю по одному в Terrasoft-приемник потребление памяти более-менее приемлимое (500-600 МБ).
Вот мне и интересно, как корректнее с точки зрения потребления памяти производить массовое чтение-запись из/в Terrasoft?
Вариант с проведением подобных операций средствами сервера БД не подходит.
Петр, скорее всего Вы делаете что-то неправильно, но судя из описания трудно понять что именно.
5000 записей (зависит конечно от структуры) очень малое количество, чтобы забирать 2 Гб.
Возможно Вы не закрываете датасет после выборки данных или берете всегда GetNewItemByUSI на каждую запись. Пришлите, пожалуйста, пример кода как и что Вы делаете для анализа.
"Ерошенко Петр Семенович" написал:Мне нужно перенести ее содержимое в Terrasoft из внешней программы посредством COM
...
Вариант с проведением подобных операций средствами сервера БД не подходит.
Петр, почему не подходит? В mssql есть поддержка COM. Что это за внешняя программа?
"Осауленко Александр" написал:Петр, почему не подходит? В mssql есть поддержка COM. Что это за внешняя программа?
Ну, во-первых Terrasoft не везде на MS SQL. Во-вторых, попадаются достаточно сложные условия на установку соответствия между сущностью в источнике и сущностью в приемнике. Например, контрагента сначала нужно искать по сочетанию ИНН/КПП. Если нашлась только одна запись, то все отлично. Если нет - то поиск продолжается только по ИНН, причем могут попадаться оригинальные ИНН типа "1", "11111111" и т. п. Оно на T-SQL, в принципе, реализуемо, но провожусь я с этим гораздо дольше, чем с кодом в TS. В самом крайнем случае из TS я могу показать список вариантов, в котором пользователь может выбрать нужный. И в-третьих, самое противное, наличие программной логики в обработчиках событий AfterAppend, AfterPost, AfterDelete, AfterEdit. Продублировать ее в SQL?
Если есть возможность, в таблицу-источник данных добавьте поле IsProcessed. Перед обработкой, для всех записей сбросьте это поле в 0. При обращение к таблице-источнику пишите условие
Select top 1000 ... From ... Where IsProcessed <>1and ...
После перекачки каждой записи надо будет IsProcessed перевести в 1.
Т.е. вы в бесконечном цикле while открываете свой датасет пока RecordCount > 0.
Какие плюсы : каждый раз после закрытия датасета очищается память (точнее спустя какое-то время пока сборщик мусора ее не освободит), следовательно можно избежать OutOfMemory.
Минусы: Чуть дольше будет идти импорт за счет обновления поля IsProcessed.
Я примерно так и поступаю, только у меня есть таблица, в которой хранятся ID объектов в источнике и приемнике. После завершения импорта очередного объекта создается запись в этой таблице. Плюсов больше: не нужно модифицировать таблицу-источник (их может быть много) и поиск объекта в приемнике нужно выполнять один раз. Таким образом, мне нужно импортировать только те объекты, которых нет в таблице соответствий.
Другой вопрос: как это пооптимальнее применять. Сейчас у меня есть глобальная переменная в скрипте, в которой храниться объект SelectQuery. Я в нем меняю значение параметра, получаю Dataset методом Open() и читаю значение. Может течь в этом месте, потому как этот код дергается очень часто?
Сейчас у меня есть глобальная переменная в скрипте, в которой храниться объект SelectQuery. Я в нем меняю значение параметра, получаю Dataset методом Open() и читаю значение.
"Олейник Дмитрий" написал:Петр, закрывате ли Вы потом Dataset?
Нет, попробую закрывать.
"Олейник Дмитрий" написал:Также вместо Services.GetNewItemByUSI('');
попробуйте Services.GetSingleItemByUSI('');
В принципе, я объект запроса получаю один раз и храню в глобальной переменной скрипта. Вы полагаете, что будет разница от того, как я его получаю, через GetNewItemByUSI или GetSingleItemByUSI?
Петр, в таком случае нет - разницы не будет. Конечно в том случае если и объект Dataset'а Вы также получаете один раз.
Попробуйте закрывать Dataset'ы. Если не поможет - тут не обойдемся без полного исходного кода, для его анализа.