03.12.2007, 11:00 | #1 |
Участник
|
Формирование прайс-листа в Axapta. Проблемы производительности.
Задача сформировать прайс-лист, т.е. вывести все позиции, которые находятся на складе X в количестве больше Y (частный случай >0). Простейшее решение выполнить следующий запрос:
X++: Select from InventSum join InventDim Where InventSum.InventDimId == InventDim.InventDimId && InventSum.AvailPhysical > Y && InventDim.InventLocationId = X Вопрос как лучше решать данную задачу в Axapta? Кто какие подходы для этого использует? |
|
03.12.2007, 11:53 | #2 |
Участник
|
как решено у нас:
внешний цикл по номенклатуре, с фильтром заблокированных и др ограничения. внутри находим количество на складе, цену, накладываем допусловия и ограничения, если все ОК, то добавляем в tmpTable. вывод |
|
03.12.2007, 11:59 | #3 |
Участник
|
Цитата:
так как выборка идет не по индексам
С совсем тяжелых случаях (если inventSum и InventDim - очень большие) можно сделать денормализацию данных. Создать поле склад в InventSum и индексы повесить. Тем самым избавимся от джоина. Намного легче запрос получится. |
|
03.12.2007, 12:10 | #4 |
Участник
|
Мешает то, что непонятно каким должен быть этот индекс. По полю AvailPhysical? Не думаю, что индекс по вещественному полю увеличит производительность.
Сделать-то можно, только вариантов очень много и приходится выбирать какой из них лучше, чем сейчас и занимаюсь. |
|
03.12.2007, 12:21 | #5 |
Участник
|
Цитата:
Простейшее решение - взять готовый отчет Критические запасы http://forum.mazzy.ru/index.php?showtopic=1842 |
|
|
За это сообщение автора поблагодарили: konopello (1). |
03.12.2007, 12:24 | #6 |
Участник
|
Цитата:
цикл по номенклатуре с учетом всех ограничений - более 50000 записей, количество записей в прайс-листе - около 3000. Таким образом для каждой номенклатуры нужно выполнить запрос к InventSum по ItemId и суммировать кол-во. Такой запрос выполняется примерно 1 сек. (точно не анализировал, но запрос первой попавшейся НЕ на реально загруженном сервере дало именно такой результат). То есть общий цикл будет выполняться ну очень долго. Если я ошибаюсь в рассуждениях, поправьте меня. |
|
03.12.2007, 12:31 | #7 |
Участник
|
Цитата:
А какая у этого всего производительность?
|
|
03.12.2007, 12:41 | #8 |
SAP
|
Цитата:
Простейшее решение не такое.
Простейшее решение - взять готовый отчет Критические запасы http://forum.mazzy.ru/index.php?showtopic=1842 |
|
03.12.2007, 12:50 | #9 |
Участник
|
Цитата:
Сообщение от Lucky13
Задача сформировать прайс-лист, т.е. вывести все позиции, которые находятся на складе X в количестве больше Y (частный случай >0). Простейшее решение выполнить следующий запрос:
X++: Select from InventSum join InventDim Where InventSum.InventDimId == InventDim.InventDimId && InventSum.AvailPhysical > Y && InventDim.InventLocationId = X Цитата:
Сообщение от Lucky13
К тому же это только пример, реально обычно нужно еще откуда-то достать цену товара и сгруппировать данные каким-либо образом, например по той же цене, так как клиенты чаще всего не любят когда одна и та же номенклатура повторяется в прайсе несколько раз. В итоге получается очень тяжелый запрос. Кто какие подходы для этого использует?
Подумайте также о том, что InventSum у вас может постоянно блокироваться при обработке движений по номенклатуре, а вы, пытаясь сделать по ней мега-запрос выгрузки прайс-листа, в свою очередь, будете блокировать других пользователей. Поэтому, опять же, кучка мелких подзапросов будет в общем случае предпочтительнее одного мега-запроса, который сначала будет ждать освобождения кучи блокировок, а потом сам надолго заблокирует таблицу, и без того являющуюся зачастую узким местом в системе. Затем, вам наверняка потребуется предоставить пользователю возможность группировать номенклатуру в выгрузке по различным критериям: либо по бренду, либо по какому-нить классификатору номенклатуры, либо еще по чему-то... Не так давно пришлось приделывать такую сортировку, плюс немного оптимизировать выгрузку прайс-листа, в котором используется довольно много условных критериев, в результате выгрузка (на псевдокоде) получилась примерно такая: Код: инициализировать канал вывода // отдельный метод если выгрузка в csv/Excel сделать то-то если выгрузка в другую базу SQL сделать что-то другое вывести заголовок (header) // отдельный метод сбросить значения предыдущего бренда и классификатора построить запрос выборки номенклатуры // отдельный метод switch по типу сортировки если сортировка по бренду запрос - таблица_брендов join InventTable если сортировка по иерархическому классификатору номенклатуры запрос - таблица_классификации join InventTable join таблица_брендов установить фильтры по брендам // отдельный метод установить фильтры по номенклатуре // отдельный метод создать QueryRun с созданным запросом по номенклатуре цикл, пока QueryRun.next() == true если QueryRun.changed(таблица_брендов) если текущий бренд не должен экспортироваться // отдельный метод установить флаг пропуска бренда если установлен флаг пропуска бренда continue получить необходимве данные по текущей номенклатуре если номенклатура не должна экспортироваться // отдельный метод continue switch по типу сортировки если сортировка по бренду если текущий бренд != предыдущий бренд вывести заголовок бренда // отдельный метод запомнить бренд как предыдущий если сортировка по иерархическому классификатору номенклатуры если текущий код классификатора не равен предыдущему вывести стек заговлоков классификатора // отдельный метод запомнить код классификатора как предыдущий сбросить переменные, используемые для получения цен, и флаги цикл по ценовым группам если ценовая группа не должна экспортироваться // отдельный метод // и это отдельный метод если номенклатура с "неэкспортируемой" ценой должна пропускаться установить флаг пропуска номенклатуры break continue получить цену (PriceDiscTable) по данной ценовой группе // опять отдельный метод если цена (т.е. PriceDiscTable) не должна экспортироваться // copy-paste из проверки ценовых групп если номенклатура с "неэкспортируемой" ценой должна пропускаться установить флаг пропуска номенклатуры break continue обработать данные по цене номенклатуры // отдельный метод если выгрузка в csv/Excel сделать то-то если выгрузка в другую базу SQL сделать что-то другое если установлен признак пропуска номенклатуры continue выгрузить данные по текущей номенклатуре // отдельный метод вывести заголовок (footer) // отдельный метод деинициализировать канал вывода // отдельный метод |
|
03.12.2007, 15:12 | #10 |
Участник
|
Цитата:
Сообщение от gl00mie
Подумайте также о том, что InventSum у вас может постоянно блокироваться при обработке движений по номенклатуре, а вы, пытаясь сделать по ней мега-запрос выгрузки прайс-листа, в свою очередь, будете блокировать других пользователей. Поэтому, опять же, кучка мелких подзапросов будет в общем случае предпочтительнее одного мега-запроса, который сначала будет ждать освобождения кучи блокировок, а потом сам надолго заблокирует таблицу, и без того являющуюся зачастую узким местом в системе.
|
|
03.12.2007, 15:33 | #11 |
Участник
|
Это было навеяно местной спецификой экспорта прайс-листов в другие SQL-базы На форуме упоминалось, что если делать запрос с inner join и выбирать в нем одну из таблиц для обновления, то заблокированными оказываются все таблицы из запроса.
|
|
03.12.2007, 16:47 | #12 |
Участник
|
Цитата:
Сообщение от gl00mie
Если она исчисляется не миллионами, то лучше, вероятно, сделать выгрузку, перебирающую все номенклатуры (с определенными фильтрами, скажем, по бренду), а уже внутри этого перебора делающую проверку на остатки по определенному складу, на соответствие выгружаемых цен определенным критериями, etc.
Запрос: X++: while select inventTable where ... { } Если в цикл добавить запрос на выборку запасов в наличии X++: select sum(AvailPhysical) from inventSum join maxof(recid) from InventDim where inventSum.InventDimId == inventDim.inventDimId && inventSum.ItemId == inventTable.ItemId && inventSum.Closed == NoYes::No && inventDim.InventLocationId == 'склад' Так вот - такой цикл выполняется очень долго. Честно ждал полчаса, но безрезультатно. "Мега-запрос" хотя и имеет массу недостатков, но выполняется максимум за 3 минуты. Вопрос что здесь не так, почему такое расхождение теории с практикой? |
|
04.12.2007, 13:18 | #13 |
Участник
|
Цитата:
Сообщение от Lucky13
Запрос:
X++: while select inventTable where ... { } X++: select sum(AvailPhysical) from inventSum join maxof(recid) from InventDim where inventSum.InventDimId == inventDim.inventDimId && inventSum.ItemId == inventTable.ItemId && inventSum.Closed == NoYes::No && inventDim.InventLocationId == 'склад' Цитата:
|
|
Теги |
inventsum, inventtable, номенклатура, остатки, производительность, прайс |
|
|