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

 
 
Опции темы Поиск в этой теме Опции просмотра
Старый 13.02.2013, 10:50   #1  
Xardas is offline
Xardas
Участник
 
28 / 13 (1) ++
Регистрация: 19.09.2012
Меняющийся тип соединения таблиц
Доброго времени суток.

Имеется класс с большим количеством запросов вида
X++:
select tbl1
exists join tbl2
where tbl2.field1 == tbl1.field1
Сейчас возникла необходимость модифицировать данный код:
Если значение некоторой логической переменной истина, то соединение таблиц должно производиться с помощью exists join.
Если значение этой же логической переменной ложь, то соединение должно производиться с помощью notexists join.

Можно ли произвести данную модификацию? Вариант
X++:
if (flag)
  select...
else
  select...
не устраивает, поскольку код будет раздут до неимоверных размеров с дублированием операторов, заключенных внутри while select.
Спасибо.
Старый 13.02.2013, 10:58   #2  
user_ax is offline
user_ax
Участник
Аватар для user_ax
 
599 / 39 (3) +++
Регистрация: 07.10.2012
Адрес: ZP
А через switch?
Старый 13.02.2013, 11:04   #3  
Xardas is offline
Xardas
Участник
 
28 / 13 (1) ++
Регистрация: 19.09.2012
Цитата:
Сообщение от user_ax Посмотреть сообщение
А через switch?
Не вижу принципиальной разницы между switch и if для тестирования значения логической переменной (принимающей всего 2 значения) за исключением того, что в switch придется писать еще case и break.

Вся проблема в том, что запросы идентичны за исключением exists и notexists.

Возможно, это реализуемо с помощью макроса?
Старый 13.02.2013, 11:07   #4  
Evgeniy2020 is offline
Evgeniy2020
Участник
 
309 / 68 (3) ++++
Регистрация: 10.04.2007
Адрес: Москва, САО, СЗАО
создавайте выборку программно через Query, QueryBuildDatasource
код будет более компактный
Старый 13.02.2013, 11:14   #5  
raz is offline
raz
NavAx
Аватар для raz
NavAx Club
Лучший по профессии 2014
Лучший по профессии 2009
 
1,490 / 1060 (38) ++++++++
Регистрация: 22.07.2003
Адрес: МО
Если query не нравится, то вариант
X++:
if (flag)
  select tableName ...
else
  select tableName ...

while tableName 
{

  next tableName;
}
вполне нормальный.
За это сообщение автора поблагодарили: Xardas (1).
Старый 13.02.2013, 11:42   #6  
Xardas is offline
Xardas
Участник
 
28 / 13 (1) ++
Регистрация: 19.09.2012
для Evgeniy2020:
На данный момент в коде множество запросов, и они все разные. Их объединяет только наличие exists join ко второй таблице. Придется делать на каждый запрос свой Query.

для raz:
Да, так я избегу переписывания операторов, но запросы все равно придется дублировать.

Последний раз редактировалось Xardas; 13.02.2013 в 12:21.
Старый 13.02.2013, 12:15   #7  
raz is offline
raz
NavAx
Аватар для raz
NavAx Club
Лучший по профессии 2014
Лучший по профессии 2009
 
1,490 / 1060 (38) ++++++++
Регистрация: 22.07.2003
Адрес: МО
Цитата:
Сообщение от Xardas Посмотреть сообщение
Запросы разные. Их объединяет только наличие exists join. Придется делать на каждый запрос свой Query.
Зачем. Один запрос и по условию ставите разный joinMode.
Старый 13.02.2013, 13:58   #8  
kair84 is offline
kair84
Участник
 
47 / 58 (2) ++++
Регистрация: 15.04.2010
Адрес: Belarus
Можно использовать макроподстановки
Важно помнить что макроподстановка выполняется в момент компиляции, а не в момент исполнения !
X++:
#localmacro.select
#define.Arg(%1)
    Select tableName
        where ...
    #if.arg('exists') exists #endIF
    #if.arg('notexists') notexists #endIF
    join joinTableName
        where ...
#endmacro

static void Job(Args _args)
{       

    if (flag)
        #select('exists');
    else
        #select('notexists');

    while (tableName)
    {
    
        next tableName;
    }
}
Если один и тот же запрос используется разных местах, можно оформить "глобальный" макрос в дереве AOT,
Нпример: \Macros\InventDimJoin
Старый 13.02.2013, 14:09   #9  
S.Kuskov is offline
S.Kuskov
Участник
Лучший по профессии 2017
Лучший по профессии 2015
Лучший по профессии 2014
 
3,429 / 1772 (66) ++++++++
Регистрация: 28.04.2007
Адрес: Калуга
Когда речь заходит об оптимизации не самого кода, а процесса его написания, на первый план выходят такие критерии как наглядность, модифицируемость, маштабируемость.
Единственное достоинство оператора select - нагладность, при использовании макросов пропадает. Уж лучше Query.
Старый 13.02.2013, 14:32   #10  
belugin is offline
belugin
Участник
Аватар для belugin
Сотрудники Microsoft Dynamics
Лучший по профессии 2017
Лучший по профессии 2015
Лучший по профессии 2014
Лучший по профессии 2011
Лучший по профессии 2009
 
4,622 / 2925 (107) +++++++++
Регистрация: 16.01.2004
Записей в блоге: 5
Макрос можно покороче:
X++:
#localmacro.select
    Select tableName
        where ...
    %1
    join joinTableName
        where ...
#endmacro

static void Job(Args _args)
{       

    if (flag)
        #select(exists);
    else
        #select(notexists);

    while (tableName)
    {
    
        next tableName;
    }
}
За это сообщение автора поблагодарили: kair84 (1).
Старый 13.02.2013, 14:34   #11  
twilight is offline
twilight
MCTS
MCBMSS
 
870 / 237 (9) ++++++
Регистрация: 17.10.2004
Адрес: Королёв
Еще как вариант можно join из запросов вообще убрать. А есть ли запись в связанной таблице проверять отдельно.
__________________
I could tell you, but then I would have to bill you.
Старый 13.02.2013, 14:50   #12  
kair84 is offline
kair84
Участник
 
47 / 58 (2) ++++
Регистрация: 15.04.2010
Адрес: Belarus
S.Kuskov - согласен не наглядно, сам обычно использую в таких случаях Query, предложил как вариант, т.к. топикстартер отверг все предыдущие варианты. а вот с точки зрения модифицируемости - вполне.

Последний раз редактировалось kair84; 13.02.2013 в 14:54.
Старый 13.02.2013, 15:00   #13  
Xardas is offline
Xardas
Участник
 
28 / 13 (1) ++
Регистрация: 19.09.2012
Цитата:
Сообщение от kair84 Посмотреть сообщение
Важно помнить что макроподстановка выполняется в момент компиляции, а не в момент исполнения !
Вот это и настораживает.
Получается, что макросы в принципе нединамические. Как бы макрос не был написан, в конкретном месте основной программы все равно будет либо exists, либо notexists.

Цитата:
Сообщение от twilight Посмотреть сообщение
Еще как вариант можно join из запросов вообще убрать. А есть ли запись в связанной таблице проверять отдельно.
Это вообще не вариант. Представляете, как упадет производительность данного кода?

Похоже, придется использовать вариант
X++:
if (flag)
  select...
else
  select...
Что же, спасибо всем за уделенное время.
Старый 13.02.2013, 15:01   #14  
dech is offline
dech
Участник
Аватар для dech
Самостоятельные клиенты AX
 
643 / 347 (13) ++++++
Регистрация: 25.06.2009
Адрес: Омск
Записей в блоге: 3
Цитата:
Сообщение от Xardas Посмотреть сообщение
для Evgeniy2020:
На данный момент в коде множество запросов, и они все разные. Их объединяет только наличие exists join ко второй таблице. Придется делать на каждый запрос свой Query.

для raz:
Да, так я избегу переписывания операторов, но запросы все равно придется дублировать.
Используйте QueryBuildDataSource и разбейте на методы. Если все грамотно сделать, дублирования кода не будет. Все будут сыты и довольны.
__________________
// no comments
Старый 13.02.2013, 15:19   #15  
kair84 is offline
kair84
Участник
 
47 / 58 (2) ++++
Регистрация: 15.04.2010
Адрес: Belarus
2 Xardas
в данном случае макроподстановка - это способ уменьшить количество кода
PHP код:
if (flag)
  
select...
else
  
select... 
а в зависимости от "размера" оператора select, возможно и нагляднее будет, сразу будет видно что отличие только в способе связывания
Старый 13.02.2013, 15:26   #16  
Владимир Максимов is offline
Владимир Максимов
Участник
КОРУС Консалтинг
 
1,654 / 1158 (42) ++++++++
Регистрация: 13.01.2004
Записей в блоге: 3
Цитата:
Сообщение от twilight Посмотреть сообщение
Еще как вариант можно join из запросов вообще убрать. А есть ли запись в связанной таблице проверять отдельно.
Цитата:
Сообщение от Xardas Посмотреть сообщение
Это вообще не вариант. Представляете, как упадет производительность данного кода?
Далеко не факт. Это надо проверять экспериментально. Как раз тот случай, когда "теоретические" рассуждения не могут дать однозначный ответ. Надо проверять.

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

Кстати, ведь по описанному Вами условию, Вы имеет "зеркальные" выборки. Это значит, что если Exists будет выполняться быстро, то not Exists неизбежно будет выполняться медленно. Или наоборот. И далеко не факт, что перенесение проверки внутрь цикла существенно повлияет на среднее время выполнения. Повторюсь, это проверить надо.

А "в общем случае" рассуждения на подобную тему мало полезны. Именно в силу того, что неизвестны детали задачи. Вполне возможно, что задачу можно решить и без использования Exists просто модифицировав запрос. Однако без знания конкретной постановки задачи заранее сказать нельзя можно это сделать или нет.
__________________
- Может, я как-то неправильно живу?!
- Отчего же? Правильно. Только зря...
Старый 13.02.2013, 15:58   #17  
sukhanchik is offline
sukhanchik
Administrator
Аватар для sukhanchik
MCBMSS
Злыдни
Лучший по профессии 2015
Лучший по профессии AXAWARD 2013
Лучший по профессии 2011
Лучший по профессии 2009
 
3,275 / 3476 (122) ++++++++++
Регистрация: 13.06.2004
Адрес: Москва
Цитата:
Сообщение от Владимир Максимов Посмотреть сообщение
Кстати, ведь по описанному Вами условию, Вы имеет "зеркальные" выборки. Это значит, что если Exists будет выполняться быстро, то not Exists неизбежно будет выполняться медленно. Или наоборот.
Необязательно. Например, на форму подтягиваются только отображаемые записи в грид (плюс-минус еще несколько). И будет там exists или notexists - это уже не столь важно.

Проверял на АХ 2009, когда делал грид из InventTable с 70 тыс записями. Я добавлял туда к каждой записи галку "Маркировать" (edit-метод) и добавлял в контекстное меню по правой кнопке мыши пункт "Фильтр по выделенному" по этому edit-методу. Маркироваться могли абсолютно непредсказуемые записи и в больших количествах (>1000). Соответственно - для целей фильтрации в коде в одном случае - делался exists join, в другом - not exists. Работало одинаково.

А вот то, что разбивать не стоит - факт.
Опять-таки - пример. Запустите расчет сводного плана, имея большой справочник номенклатур. Если у Вас заполнены Настройки-Покрытие номенклатуры (ReqItemTable) - то расчет отработает. Если не заполнены - то не отработает. Обратите внимание - сколько времени отрабатывает "вхолостую" расчет, просто бегая в цикле по большому справочнику номенклатуры. Хотя простейшая оптимизация вида InventTable exists join ReqItemTable могла бы делать пересчет сводного плана мгновенным, при условии, что записей в ReqItemTable много меньше, чем в InventTable
__________________
Возможно сделать все. Вопрос времени

Последний раз редактировалось sukhanchik; 13.02.2013 в 16:02.
Старый 13.02.2013, 16:15   #18  
Владимир Максимов is offline
Владимир Максимов
Участник
КОРУС Консалтинг
 
1,654 / 1158 (42) ++++++++
Регистрация: 13.01.2004
Записей в блоге: 3
Цитата:
Сообщение от sukhanchik Посмотреть сообщение
А вот то, что разбивать не стоит - факт.
Нет. Не факт Я же говорю, когда речь идет об exist, то все надо проверять экспериментально. Практический результат (скорость выполнения) - слабо предсказуем "теоретическими" рассуждениями.

Тут "фишка" в том, что физически на MS SQL сервере выполняется не "голый" запрос, а запрос "обернутый" в курсор (DECLARE CURSOR ... FOR). Как следствие, планы выполнения "голого" запроса и курсора могут существенно отличаться. Однако здесь ключевое слово "могут". Могут отличаться, а могут и не отличаться. Зависит от кучи условий, не всеми из которых можно управлять.

Лично я "напоролся" на подобные различия именно в запросах с Exists. В запросах, где exists отсутствует я подобных различий не наблюдал. Отсюда и повышенная настороженность к подобным запросам.
__________________
- Может, я как-то неправильно живу?!
- Отчего же? Правильно. Только зря...
Старый 13.02.2013, 17:17   #19  
mazzy is offline
mazzy
Участник
Аватар для mazzy
Лучший по профессии 2015
Лучший по профессии 2014
Лучший по профессии AXAWARD 2013
Лучший по профессии 2011
Лучший по профессии 2009
 
29,472 / 4494 (208) ++++++++++
Регистрация: 29.11.2001
Адрес: Москва
Записей в блоге: 10
Цитата:
Сообщение от kair84 Посмотреть сообщение
Можно использовать макроподстановки
Не надо использовать макросы (если это не константы)
причины уже назыавали.
Старый 13.02.2013, 20:46   #20  
gl00mie is offline
gl00mie
Участник
MCBMSS
Most Valuable Professional
Лучший по профессии 2017
Лучший по профессии 2015
Лучший по профессии 2014
Лучший по профессии AXAWARD 2013
Лучший по профессии 2011
Лучший по профессии 2009
 
3,684 / 5788 (200) ++++++++++
Регистрация: 28.11.2005
Адрес: Москва
Записей в блоге: 3
Цитата:
Сообщение от Xardas Посмотреть сообщение
Имеется класс с большим количеством запросов вида
X++:
select tbl1
exists join tbl2
where tbl2.field1 == tbl1.field1
Сейчас возникла необходимость модифицировать данный код: Если значение некоторой логической переменной истина, то соединение таблиц должно производиться с помощью exists join. Если значение этой же логической переменной ложь, то соединение должно производиться с помощью notexists join. Можно ли произвести данную модификацию?
Есть время разбрасывать камни и время их собирать. Кто-то поленился нормально написать код, избавиться от дублирования, вынести принятие однотипных решений в одно место, а теперь придется либо наплодить кучу copy-paste'а, либо засучить рукава и провести серьезный рефакторинг кода.
Цитата:
Сообщение от Xardas Посмотреть сообщение
Похоже, придется использовать вариант
X++:
if (flag)
  select...
else
  select...
Что же, спасибо всем за уделенное время.
Не стоит так делать. Тут уже писали, наиболее нормальный вариант, позволяющий менять тип join'а во время выполнения, - это переписать код на Query'ках. Решать проблему copy-paste'ом - все равно, что заметать сор под половик в надежде, что убирать его придется кому-то другому; это непрофессионально, в конце концов
За это сообщение автора поблагодарили: S.Kuskov (1).
 

Похожие темы
Тема Автор Раздел Ответов Посл. сообщение
AX 2012 Наследование таблиц. Краткое описание механизма sukhanchik DAX: Программирование 32 21.09.2018 17:56
Таблица, расширенный тип данных, базовый перечислимый тип или класс, вызванные test_Sdelka, уже существуют. Импортирование Table прервано. Poleax DAX: Программирование 4 17.05.2011 17:57
Тип производственного заказа Anais DAX: Функционал 17 26.05.2005 13:50
Никак не могу вьехать, для чего нужны тип счета и тип разноски maloy DAX: Функционал 5 28.03.2004 17:18
Тип связи Андре DAX: Программирование 9 25.04.2002 20:20

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

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

Рейтинг@Mail.ru
Часовой пояс GMT +3, время: 07:53.
Powered by vBulletin® v3.8.5. Перевод: zCarot
Контактная информация, Реклама.