AXForum  
Вернуться   AXForum > Microsoft Dynamics AX > DAX: Программирование
All
Забыли пароль?
Зарегистрироваться Правила Справка Пользователи Сообщения за день Поиск

 
 
Опции темы Поиск в этой теме Опции просмотра
Старый 20.07.2005, 17:34   #1  
kashperuk is offline
kashperuk
Участник
Аватар для kashperuk
MCBMSS
Соотечественники
Сотрудники Microsoft Dynamics
Лучший по профессии 2017
Лучший по профессии 2015
Лучший по профессии 2014
Лучший по профессии 2011
Лучший по профессии 2009
 
4,361 / 2084 (78) +++++++++
Регистрация: 30.05.2004
Адрес: Atlanta, GA, USA
? Оптимизация запроса - ranges
Привет, всем.
Если кто видел, как формируется запрос для, к примеру, Оборотно - сальдовой ведомости, прошу помочь:

Делаю запрос наподобие - только у меня строки должны отображаться в определенном порядке, и не все из них.

Проблема в том, что если строк больше 350 (приблизительно), то парсер обрезает эту строку запроса, и вылетает с ошибкой понятно.

Вот, примеры:
1).
SELECT * FROM KM_FundOnHandMovement ORDER BY KM_FundOnHandMovement.LineNum ASC WHERE ((LineNum = 1 OR LineNum = 2 OR LineNum = 3 OR LineNum = 4 OR LineNum = 5 OR LineNum = 6 OR ..... OR LineNum = 104))

Получим:
SELECT * FROM KM_FundOnHandMovement ORDER BY KM_FundOnHandMovement.LineNum ASC WHERE ((LineNum >= 1 AND LineNum <= 281))

2).
SELECT * FROM KM_FundOnHandMovement ORDER BY KM_FundOnHandMovement.LineNum ASC WHERE ((LineNum = 1 OR LineNum = 2 OR LineNum = 8 OR LineNum = 13 OR LineNum = 14 OR LineNum = 15 OR LineNum = 16 OR LineNum = 17 OR LineNum = 18 OR LineNum = 19 OR LineNum = 20 OR LineNum = 21 OR LineNum = 22 OR LineNum = 23 OR LineNum = 24 OR LineNum = 25 OR LineNum = 26 OR LineNum = 27 OR LineNum = 28 OR LineNum = 29 OR LineNum = 30 OR LineNum = 31 OR LineNum = 72 OR LineNum = 73 OR .... LineNum = 104))

Получится должно такое:

select * FROM KM_FundOnHandMovement ORDER BY KM_FundOnHandMovement.LineNum ASC WHERE (((LineNum >= 1 AND LineNum <= 2) OR LineNum == 8 OR (LineNum >= 13 AND LineNum <= 31) OR (LineNum >= 72 AND LineNum <= 104)))

3).
SELECT * FROM KM_FundOnHandMovement ORDER BY KM_FundOnHandMovement.LineNum ASC WHERE ((LineNum = 1 OR LineNum = 2 OR LineNum = 8 OR LineNum = 13 OR LineNum = 16 OR LineNum = 19 OR LineNum = 24 OR LineNum = 31 OR LineNum = 32 OR LineNum = 35 OR LineNum = 45 OR LineNum = 47 OR LineNum = 49 OR LineNum = 51 OR LineNum = 53 OR LineNum = 55 OR LineNum = 58 OR LineNum = 61 OR LineNum = 72 OR LineNum = 73 OR LineNum = 76 OR LineNum = 83 OR LineNum = 86 OR LineNum = 88 OR LineNum = 91 OR LineNum = 94 OR LineNum = 104))

А такое так и останется!



Как написать такой оптимизатор? В смысле, как выловить все интервалы, и пропустить все одиночные цифры?

Какие - то другие идеи может по оптимизации.

P.S. Забыл добавить про сам запрос - формируется через QueryBuildRange понятное дело

P.P.S. И еще, строки, которые нужно отображать, все есть - в Set(Types::Integer)
Старый 20.07.2005, 17:44   #2  
Maxim Gorbunov is offline
Maxim Gorbunov
Administrator
Соотечественники
Лучший по профессии 2009
 
2,483 / 645 (26) +++++++
Регистрация: 27.11.2001
Адрес: Dubai, UAE
Сделайте временную таблицу (можно, например, TmpRecId воспользоваться), заполните ее нужными Вам номерами строк и добавьте в запрос Exists Join'ом.
__________________
Not registered yet? Register here!
Have comments, questions, suggestions or anything else regarding our web site? Don't hesitate, send them to me
Старый 20.07.2005, 17:47   #3  
kashperuk is offline
kashperuk
Участник
Аватар для kashperuk
MCBMSS
Соотечественники
Сотрудники Microsoft Dynamics
Лучший по профессии 2017
Лучший по профессии 2015
Лучший по профессии 2014
Лучший по профессии 2011
Лучший по профессии 2009
 
4,361 / 2084 (78) +++++++++
Регистрация: 30.05.2004
Адрес: Atlanta, GA, USA
Все гениальное просто.

Попробую обязательно.
Спасибо, Максим!
Старый 20.07.2005, 17:55   #4  
Wamr is offline
Wamr
----------------
Лучший по профессии 2014
Лучший по профессии AXAWARD 2013
 
1,737 / 858 (32) +++++++
Регистрация: 15.01.2002
Адрес: Москва
Записей в блоге: 7
Ох, не люблю я join с временной таблицей :-\
Поэтому сразу предупрежу, что скорее всего при запуске запроса вы получите table scan по таблице KM_FundOnHandMovement с последующим анализом каждой строки внутри мозгов Аксапты, а уж насколько это страшно в краткосрочной и долгосрочной перспективе думайте сами
Старый 20.07.2005, 19:30   #5  
db is offline
db
Роман Долгополов (RDOL)
Лучший по профессии 2015
Лучший по профессии AXAWARD 2013
 
393 / 692 (24) +++++++
Регистрация: 01.04.2004
Адрес: Москва
Цитата:
Изначально опубликовано kashperuk
[B]Все гениальное просто. B]
Ох уж эти гении.... Предложили типичный пример борьбы с производительностью системы. именно "с", а не "за"

Может лучше по нашему, по рабоче-крестьянски, но зато с толком и расстановкой


Аксапты под рукой нет, поэтому вместо примера получилось вот такое руководство по программированию

делаете постоянную таблицу, например RecIdFilterTable (saveDataPerCompany=NO)
с тремя int столбцами
RefRecId
SessionId
Cookie

Строим индексы
первый по RefRecId
второй составной по SessioId и Cookie

заносите в таблицу RecId тех записей, которые нужно будет отобрать в каком нито вашем крутом запросе
в SessionId заносите код текущей сессии Axapta - получаем из одноименной функции
в Cookie любую хрень, уникальную в пределах сессии - можно, например,
через Sequence создать свою системную серию или "украсть" очередной RecId через SystemSequence

Связка SessionId - Cookie будет уникальным идентификатором набора RecId в пределах всей Аксапты, запоминаем их значения.
На самом деле достаточно и Cookie, но об этом позже

Теперь пишем свой запрос и дописываем к нему кусок со связкой к RecIdFilterTable

selеct МояСуперТаблица
....
....
exists join RecIdFilterTable
where МояСуперТаблица.RecId == RecIdFilterTable.RefRecId
&& RecIdFilterTable.SessionId == Запомненный код сессии
&& RecIdFilterTable.Cookie == Запомненный COOKIE

Не забываем создать индекс по RecId в МояСуперТаблица
Записи в RecIdFilterTable вставляем через RecordInsertList

В результате имеем все что хотели - быструю выборку неограниченного количества произвольных записей

Осталось только определиться с уборкой мусора в этой таблице

1. После того как запрос отработал чистим таблицу, передавая в качестве критерия для команды delete_from запомненные значения SessionID и Cookie

2. Для того, чтобы убирать мусор, который может появится в случае аварийного падения аксапты между набиванием RecId в таблицу и последующим стриранием этих данных, при старте сессии чистим эту таблицу, используя в качестве критерия только SessionId. Такую чистку следует вызвывать из application.startupPost()

Прочитав все это огромная просьба сначала попробовать, прежде чем начать все это "опускать" (как так, лишняя таблица, запись куда то, лучше мы напишем супервыернутый запрос на 3 экрана с 200 ранжами и т.д., или как предлагали временную таблицу сделаем) Все затраты вычислительных ресуров связанные с описанной инфраструктурой при ее грамотной реализации многократно компенсируются за счет существенного уменьшения времени выполнения запроса.

Для любителей экономить RecId которые так безалаберно растранжириваются здесь на временные записи: класс SystemSequence позволяет запретить генерацию RecId для определенных таблиц - точно сейчас не скажу - нет аксапты под руками - кажется
suspendRecIdGeneration(). Вызовите ее с tablenum(RecIdFilterTable) и никто не тронет драгоценных RecId. Вместо них будут набиваться по очереди 2 "левых" значения, но в данном случае это абсолютно не важно

Кто будет делать, не поленитесь оформить все это в виде класса - вещь универсальная на 100 %
и не забудьте там метод который приделывает фильтр к произвольному QueryBuildDataSource

Добавка:
Про автоматичкскую генерацию "левых" RecId наврал. это оказался побочный эффект одного алгоритма. Так что если не хотите тратить настоящие RecId заполняйте это поле вручную любым значением

Последний раз редактировалось db; 12.07.2006 в 15:10.
За это сообщение автора поблагодарили: tricky (1), virtuoso (1).
Старый 21.07.2005, 01:31   #6  
kashperuk is offline
kashperuk
Участник
Аватар для kashperuk
MCBMSS
Соотечественники
Сотрудники Microsoft Dynamics
Лучший по профессии 2017
Лучший по профессии 2015
Лучший по профессии 2014
Лучший по профессии 2011
Лучший по профессии 2009
 
4,361 / 2084 (78) +++++++++
Регистрация: 30.05.2004
Адрес: Atlanta, GA, USA
Сделал все-таки через existJoin с табличкой с номерами строк.

2db:
За совет спасибо. Только поздно. Только сейчас прочитал. А переделывать как сами понимаете желания нет. Возможно в будущем учту.
Отдельная благодарность за то, что напомнили про RecordInsertList - увеличило быстродействие реально в разы.

Не судите строго.
Старый 21.07.2005, 11:20   #7  
Wamr is offline
Wamr
----------------
Лучший по профессии 2014
Лучший по профессии AXAWARD 2013
 
1,737 / 858 (32) +++++++
Регистрация: 15.01.2002
Адрес: Москва
Записей в блоге: 7
К истокам
Есть еще способ, о котором часто забывают
PHP код:
static void Job143(Args _args)
{
    
Query       q = new Query();
    
QueryRun    qr;
    
int         ij;
    
str         range;
    ;

    
q.addDataSource(tableNum(InventTable));
    for( 
020i++)
    {
        
range '';
        for( 
1<= 100j++)
        {
            
range += (range ',' '') + int2str(i*100 j);
        }
        
q.dataSourceNo(1).addRange(fieldNum(InventTableRecId)).value(range);
    }

    
qr = new QueryRun(q);

    
qr.next();

    
info(qr.query().dataSourceNo(1).toString());

Т.е. на одно поле можно накладывать несколько раз range, которые в запросе будут объединяться по ИЛИ.

Как видно из примера для MS-SQL можно спокойно запихнуть 2000 ограничений, а для Oracle мне удалось и более 5000. И никаких join
Старый 21.07.2005, 11:53   #8  
db is offline
db
Роман Долгополов (RDOL)
Лучший по профессии 2015
Лучший по профессии AXAWARD 2013
 
393 / 692 (24) +++++++
Регистрация: 01.04.2004
Адрес: Москва
2 Wamr


1. Сравните производительность запроса с 2000 ранжами по ИЛИ с join-ом
2. Голову на отсечение дадите, что никакой "вумный товарищ" не выберет 2001 строчку

Все эти искусственные ограничения имеют в основе только невежество и собственную лень. И к сожалению, стандартный функционал, потталкивает к такой работе. Чья то идиотская идея начинает копироваться, размножаться и т.д.

2 kashperuk:
можно все таки посужу строго?

Какими критериями вы руководствуетесь для определения готовности той или иной модификации? Только что на экране появились правильные цифирьки? У вас есть план тестирования производительности? Вы проводите нагрузочные испытания для каждой новой модификации или все это творчество благополучно будут испытывать пользователи после запуска? Вы собирали требования к производельности - время отклика, загрузку, чувствительность к загрузке, мощность, масштабируемость и т.д

Так уж случилось, что 90 % моих проектов отличаются нехилыми для аксапты объемами данных - были базы от сотни гигабайт уже при запуске. Пришлось выработать для себя принцип тестировать все сразу на предполагаемом среднем рабочем объеме данных умноженным на 6, при этом время выполнения операции должно быть в 6 раз меньше максимально допустимого.
Возможно слишком жестко и жестоко в первую очередь по отношению к себе, но позволяет не сильно гадать на кофейной гуще. На самом деле я никогда не могу знать куда дальше пойдет то или иное решение, и какой сумасшедший сейлз продаст что нито, разработанное для системы с 50 пользователями клиенту, который загонит туда 500 человек. Да все не предусмотришь, но по крайней мере у меня в 90% случаев останется запас. И самое интересное, когда привыкаешь так делать, то дополнительные затраты оказываются просто "на уровне шума"
Старый 21.07.2005, 12:45   #9  
Wamr is offline
Wamr
----------------
Лучший по профессии 2014
Лучший по профессии AXAWARD 2013
 
1,737 / 858 (32) +++++++
Регистрация: 15.01.2002
Адрес: Москва
Записей в блоге: 7
Цитата:
Сравните производительность запроса с 2000 ранжами по ИЛИ с join-ом
Сравнил, хотя и так было ясно.. а теперь сравните на 100-200 записей и сравните накладные расходы на заполнение, очистку и периодическую чистку от мусора "временной" таблицы.
Нет универсального решения на все случаи жизни. Всегда надо анализировать текущие объемы и будущие объемы обрабатываемой информации.
Старый 21.07.2005, 12:53   #10  
db is offline
db
Роман Долгополов (RDOL)
Лучший по профессии 2015
Лучший по профессии AXAWARD 2013
 
393 / 692 (24) +++++++
Регистрация: 01.04.2004
Адрес: Москва
как знаете, как хотите, все закругляюсь Пока проектик в поллимона баксов на зафакапите разговоры судя по всему бессмыслены. Пошел дальше отдыхать
Старый 21.07.2005, 13:06   #11  
ALES is offline
ALES
Участник
Злыдни
 
220 / 45 (2) +++
Регистрация: 11.08.2004
:)
Цитата:
Изначально опубликовано db
Пошел дальше отдыхать
Ох уж эти гении....
Старый 23.07.2005, 10:25   #12  
Maxim Gorbunov is offline
Maxim Gorbunov
Administrator
Соотечественники
Лучший по профессии 2009
 
2,483 / 645 (26) +++++++
Регистрация: 27.11.2001
Адрес: Dubai, UAE
kashperuk, не волнуйтесь, идея, в конечном счете, все равно одна и та же. Зато, если возникнут проблемы с производительностью, Вы точно знаете, где искать и что поправить
__________________
Not registered yet? Register here!
Have comments, questions, suggestions or anything else regarding our web site? Don't hesitate, send them to me
Старый 23.07.2005, 16:24   #13  
kashperuk is offline
kashperuk
Участник
Аватар для kashperuk
MCBMSS
Соотечественники
Сотрудники Microsoft Dynamics
Лучший по профессии 2017
Лучший по профессии 2015
Лучший по профессии 2014
Лучший по профессии 2011
Лучший по профессии 2009
 
4,361 / 2084 (78) +++++++++
Регистрация: 30.05.2004
Адрес: Atlanta, GA, USA
Talking
Да я, собственно, и не думал.
Идея хорошая, работает отлично, и, кстати сказать, довольно быстро - заполняю табличку через RecordInsertList.
Поэтому, спасибо еще раз.
Старый 31.01.2011, 20:19   #14  
IKA is offline
IKA
Участник
 
359 / 65 (3) ++++
Регистрация: 15.03.2006
db:
(Старая тема, но все еще , думаю, актуальная.)
Цитата:
Для того, чтобы убирать мусор, который может появится в случае аварийного падения аксапты между набиванием RecId в таблицу и последующим стриранием этих данных, при старте сессии чистим эту таблицу, используя в качестве критерия только SessionId. Такую чистку следует вызвывать из application.startupPost()
Мне кажется, в качестве Cookie удобно использовать LoginDateTime, а потом очищать таблицу по SessionId and LoginDateTime, как сделано в BatchRun классе, метод serverCleanUpDeadTasks:
X++:
  update_recordset batch setting RetryCount = batch.RetryCount + 1, Status = BatchStatus::Ready
    where batch.Status == BatchStatus::Executing
        && batch.RetryCount < batch.RetriesOnFailure
    notexists join clientSessions
        where batch.SessionIdx == clientSessions.SessionId
            && batch.SessionLoginDateTime == clientSessions.LoginDateTime
            && clientSessions.Status != 0;
очищать в самом классе при повторном вызове, а не application.startupPost().

Последний раз редактировалось IKA; 31.01.2011 в 20:25.
За это сообщение автора поблагодарили: virtuoso (1).
 

Похожие темы
Тема Автор Раздел Ответов Посл. сообщение
Изменить план выполнения запроса Sequel DAX: Администрирование 2 29.05.2008 15:46
palleagermark: Dynamic date ranges in queries Blog bot DAX Blogs 8 07.05.2008 17:03
Оптимизация запроса oleg_e DAX: Программирование 16 11.01.2008 10:22
Опять оптимизация запроса KpecT DAX: Программирование 3 02.11.2007 14:41
Оптимизация запроса Янка DAX: Программирование 1 27.04.2006 08:37

Ваши права в разделе
Вы не можете создавать новые темы
Вы не можете отвечать в темах
Вы не можете прикреплять вложения
Вы не можете редактировать свои сообщения

BB коды Вкл.
Смайлы Вкл.
[IMG] код Вкл.
HTML код Выкл.
Быстрый переход

Рейтинг@Mail.ru
Часовой пояс GMT +3, время: 15:28.