Статья посвящена прямым вызовам сервера из программ X++ без применения SQL-запросов Dynamics AX (ранее известная как AXAPTA). Это позволяет превратить Dynamics AX в клиент-серверную систему и получить преимущества за счет распределенной обработки данных: повышение скорости обработки, разгрузку вычислительного комплекса. Кроме того, за счет использования в прямых запросах к серверу современных реализаций языка SQL, таких как Transact-SQL для MS SQL или PL/SQL для ORACLE (вместо ограниченного варианта SQL Dynamics AX), достигается большая гибкость и эффективность обработки данных. Приводятся примеры построения отчетов, процедур вставки и модификации данных. В статье речь идет о версиях Dynamics AX до 3.0 SP5 включительно.

А.Минин, К.Токмачев (palevo@mail.ru)

Introduction:

Клиент-серверные системы появляются в России во второй половине 90-х годов прошлого века. В это время популярные сетевые/локальные интегрированные системы CLIPPER, FOXPRO, CLARION, DBASE и т.п., работающие в режиме файл-сервер (ФС), начинают заменяться на клиент-серверные связки типа DELPHI/INTERBASE, C++/SQL-SERVER и т.п. Эти замены имели два принципиальных новшества: объектно-ориентированное программирование (ООП) и режим клиент-сервер (КС). ООП позволило создать эволюционирующий прикладной код. В отличие от программ на CLIPPER 5.03 и FOXPRO 2.6 , новые проекты стало возможно начинать не с чистого листа, а с изготовленных ранее, прошедших отбор прикладных суперклассов. Режим КС позволял резко повысить производительность прикладных программных систем за счет распределения обработки данных между машинами - клиентом и сервером. Одним из ярких достижений в ряду ERP-систем является система AXAPTA, представляющая собой объектно-ориентированный язык X++, интегрированный с подъязыком языка SQL–интерфейсом работы с серверами баз данных. Наша статья посвящена использованию режима КС в AXAPTA.

Method:

Обозначим проблему. Когда прикладная программа на CLIPPER или FOXPRO обрабатывают данные сервера, весь объем данных перекачивается по сети с сервера в оперативную память клиента. Такой режим обработки данных назовем режимом файл-сервер (ФС). Однако нередко целью обработки является выборка или статистика. В подобных случаях оптимально провести обработку данных на сервере, и лишь короткий результат передать по сети клиенту. Это уже будет режим КС. Получаем два преимущества КС над ФС: сокращение сетевого трафика, и загрузка работой высокопроизводительного компьютера-сервера, а не «тормозного» клиента.

В этой статье мы не будем давать точного определения оптимальности программного кода. Согласно Лейбницу, действовать оптимально означает действовать так, как действует Бог. Но даже Богу Лейбниц готов сделать «несколько замечаний по управлению ходом вещей». Подойдем к понятию оптимальности интуитивно. Прикладной программный код (алгоритм) назовем НЕ ОПТИМАЛЬНЫМ, если существует другой код (алгоритм), решающий ту же проблему при тех же условиях в десятки и сотни раз быстрее.

В языках программирования сетевых/локальных интегрированных систем (типа CLIPPER или FOXPRO) нет интерфейсов для работы с серверами баз данных, позволяющих выполнять запросы удаленно,  даже встроенный язык SQL системы FOXPRO 2.6, являющийся настоящим шедевром программирования благодаря эффективной Rushmore Technology, выполняет SQL – запросы локально. Высокая производительность Rushmore Technology объясняется, в частности, автоматическим построением индексов и их размещением на локальном компьютере.

В Dynamics AX в среде разработки X++ есть подъязык SQL для работы с сервером баз данных. Однако он имеет серьезные ограничения. Несложно показать, что этот подъязык синтаксически (и, тем более, семантически) не отвечает не только стандарту SQL-2000, но даже устаревшему на сегодня стандарту SQL-1992. Например, в статистических запросах из двух независимых квалификаций GROUP BY и ORDER BY используется только одна, отсутствуют комбинированные операторы «select … into …», «update … from …» и др.

Мы, разумеется, не утверждаем, что подобные действия вообще не могут быть запрограммированы на языке X++ (по одной записи, в памяти клиента, локально), мы говорим, что они не могут быть запрограммированы в режиме КС.

Кроме того, в языке X++ вообще не представлены средства языка SQL, предназначенные для создания т.н. «хранимых процедур» (SP) – пользовательских программ обработки данных, исполняемых на сервере.

Все это свидетельствует о том, что язык X++ не позволяет создать код, в пределах которого обработка данных была бы оптимально распределена между сервером и клиентом. Следовательно, систему Dynamics AX (рассмотренную в пределах языка X++) нельзя считать полновесной КС системой.

Очевидно, для многих функционалов Dynamics AX (например, «расчеты с персоналом», «основные средства», «управление запасами» и др.) задача оптимизации времени выполнения за счет распределения обработки данных между машинами (между «клиентом» и «сервером») – не ставилась и не решалась разработчиками. Следствием этого является неоправданно медленная работа многих режимов этих функционалов, исчисляемая в минутах, в десятках минут, в часах.

Заметим, что в прикладной программной системе могут быть процедуры двух типов: интерактивные и пакетные. Для интерактивных процедур существенна не скорость, но дизайн интерфейса с пользователем: окна, кнопки, подсказки и т.п. Интерактивная процедура программируется в расчете на одну запись, «медленно» вводимую оператором. Время обработки записи имеет физиологический масштаб, например, секунда. (Миллисекунда – не имеет смысла.)

Напротив, для пакетных процедур существенна производительность программного кода. Обрабатываются тысячи и миллионы записей, и ориентировка на физиологический масштаб превращается в часы ожидания. Очевидно, что в интерактивных и пакетных процедурах должны использоваться разные алгоритмы. Претензий к интерактивным режимам Dynamics AX   – нет, а вот пакетные режимы, возможно в силу ограничений языка X++, запрограммированы менее удачно (перенос их выполнения «на сервер» в ночное время в классе RunBaseButch – не решает проблему полностью, но лишь подтверждает ее наличие).

Определенным шагом к повышению эффективности обработки данных в Dynamics AX является переход от режима «двухзвенки» к режиму «трехзвенки». В этом случае решение задачи распределяется по трем машинам, так что между клиентом и сервером вставляется промежуточная машина, на которой размещаются общесистемные ресурсы (например, application). Это позволяет сэкономить ресурсы компьютера-клиента (не размещать на нем application) и сделать его матобеспечение «тонким». Однако логика процедур работы с сервером остается прежней, один и тот же программный код работает и в «двухзвенке» и в «трехзвенке». Заметим, что оптимальное решение конкретной вычислительной задачи зависит от возможностей вычислительного комплекса и, вообще говоря, достигается в «n – звенке», а не в «двухзвенке» или «трехзвенке».

Очевидно, отрицательные последствия неоптимального программирования особенно велики в системах, претендующих быть типовыми (к которым, несомненно, относится Dynamics AX). Широкое внедрение не оптимально запрограммированных систем приводит к расточительной трате вычислительных ресурсов предприятий и рабочего времени персонала. Не вдаваясь в экономический аспект проблемы, напомним известную фразу, которую М.Вебер приписывает Б.Франклину: «Time is Money».

Поскольку язык X++ не позволяет применить режим КС, возможности повышения производительности Dynamics AX будем искать за пределами X++.

Results:

Рассмотрим три примера повышения производительности системы Dynamics AX.

  1. Постоянный отчет с пользовательским дизайном.

Результат: быстрое вычисление отчета произвольной сложности и произвольного дизайна, включающего, возможно, десятки взаимосвязанных файлов.

  1. Произвольный запрос/автоотчет в excel.

Результат: максимально быстрое вычисление отчетов произвольной сложности (в частности, с любым числом столбцов), но упрощенного дизайна; распечатка отчета или отображение данных в EXCEL.

  1. Импорт данных в Dynamics AX.

Результат: скоростной импорт функционалов с данными из одной системы в другую, импорт нормативно-справочной информации на стадии разработки/настройки функционалов.

Разъяснения и используемые средства:

Примеры текстов программ:

(*) Пример 1. Определение системных параметров подключения Axapta к SQL-серверу методом sqlSystem.createLoginProperty():

LoginProperty lp;
SqlSystem sqlSystem;
str sqlConnect;
;
sqlSystem = new SqlSystem();
lp = sqlSystem.createLoginProperty();


sqlConnect = "Driver={SQL Server}" +
   ";UID=" + lp.getUsername() +
   ";PWD=" + lp.getPassword() +
   ";SERVER=" + lp.getServer() +
   ";DATABASE=" + lp.getDatabase();

(**) Пример 2.  Вызов EXCEL  как COM-объекта через ADO – интерфейс и чтение RECORDSET из EXCEL:

COM excel, workbooks, workbook, worksheets, worksheet, cells, cell, ranges;
COM rs;
 excel = new COM("Excel.Application");
excel.visible(false);
 workbooks = excel.workbooks();
workbook  = workbooks.open(#ReportTemplatePath_ru + "Имя_шаблона.xlt");
worksheets = workbook.worksheets();
worksheet = worksheets.item(1);
worksheet.select(1);
 ranges = worksheet.range("A4");
ranges.CopyFromRecordset(rs);

Отметим дополнительно, что CopyFromRecordset(rs) - быстрая операция по сравнению с построчным и поячеечным переносом данных в Excel; кроме того, стандартный класс Axapta ComExcelDocument_RU не имеет метода для работы с RecordSet;

 

(***) Пример 3.  Нахождение max RECID в базе данных для компаний VRT и OM4:

create table #1 (tbl sysname,mvrt int, mom4 int)
 
DECLARE x_cursor CURSOR FOR
   select a.name as tab,count(b.name) as col from sysobjects a
   inner join syscolumns b on b.id=a.id where b.name in ('recid','dataareaid')
   group by a.name having count(b.name)=2 order by 1
 
DECLARE @TAB sysname, @COL int, @xsql nvarchar(500)


OPEN x_cursor
   FETCH NEXT FROM x_cursor INTO @TAB, @COL


WHILE @@FETCH_STATUS = 0 
BEGIN
   set @xsql=N'insert into #1'+
      'select @tbl, max(case dataareaid when @vrt then recid else 0 end),'+
      '             max(case dataareaid when @om4 then recid else 0 end)'+
      'from '+ @TAB'
   exec sp_executesql @xsql,
      N'@tbl sysname,@vrt sysname,@om4 sysname',@tbl=@TAB,@vrt='vrt',@om4='om4'
   FETCH NEXT FROM x_cursor INTO @TAB, @COL
END


CLOSE x_cursor
 DEALLOCATE x_cursor


select  max(mvrt), max(mom4) from #1

Conclusions:

Прикладной программный код ряда функционалов Dynamics AX не оптимален по двум причинам. Во-первых, алгоритмически код написан в стиле ФС; во-вторых, сама реализация языка SQL в Dynamics AX существенно беднее современных стандартов SQL.

Использование программных средств за пределами языка X++ позволяет существенно повысить производительность системы Dynamics AX. Это может быть полезно на стадии разработки и настройки функционалов, в ряде задач сопровождения и администрирования, наконец, в некоторых прикладных задачах.

Чрезмерное увлечение альтернативным программированием (за пределами X++) может вступить в противоречие с аудиторской «прозрачностью» Dynamics AX и затруднить обновление версий. Последнее замечание, строго говоря, относится к любому программированию на X++.

Acknowledgments:

Выражаем благодарность коллективу программистов ОМК за полезные советы, программную реализацию предложенных идей и участие в обсуждении результатов.

А.Минин, К.Токмачев (palevo@mail.ru)