13.02.2013, 10:50 | #1 |
Участник
|
Меняющийся тип соединения таблиц
Доброго времени суток.
Имеется класс с большим количеством запросов вида X++: select tbl1 exists join tbl2 where tbl2.field1 == tbl1.field1 Если значение некоторой логической переменной истина, то соединение таблиц должно производиться с помощью exists join. Если значение этой же логической переменной ложь, то соединение должно производиться с помощью notexists join. Можно ли произвести данную модификацию? Вариант X++: if (flag) select... else select... Спасибо. |
|
13.02.2013, 10:58 | #2 |
Участник
|
А через switch?
|
|
13.02.2013, 11:04 | #3 |
Участник
|
Не вижу принципиальной разницы между switch и if для тестирования значения логической переменной (принимающей всего 2 значения) за исключением того, что в switch придется писать еще case и break.
Вся проблема в том, что запросы идентичны за исключением exists и notexists. Возможно, это реализуемо с помощью макроса? |
|
13.02.2013, 11:07 | #4 |
Участник
|
создавайте выборку программно через Query, QueryBuildDatasource
код будет более компактный |
|
13.02.2013, 11:14 | #5 |
NavAx
|
Если query не нравится, то вариант
X++: if (flag) select tableName ... else select tableName ... while tableName { next tableName; } |
|
|
За это сообщение автора поблагодарили: Xardas (1). |
13.02.2013, 11:42 | #6 |
Участник
|
для Evgeniy2020:
На данный момент в коде множество запросов, и они все разные. Их объединяет только наличие exists join ко второй таблице. Придется делать на каждый запрос свой Query. для raz: Да, так я избегу переписывания операторов, но запросы все равно придется дублировать. Последний раз редактировалось Xardas; 13.02.2013 в 12:21. |
|
13.02.2013, 12:15 | #7 |
NavAx
|
|
|
13.02.2013, 13:58 | #8 |
Участник
|
Можно использовать макроподстановки
Важно помнить что макроподстановка выполняется в момент компиляции, а не в момент исполнения ! 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; } } Нпример: \Macros\InventDimJoin |
|
13.02.2013, 14:09 | #9 |
Участник
|
Когда речь заходит об оптимизации не самого кода, а процесса его написания, на первый план выходят такие критерии как наглядность, модифицируемость, маштабируемость.
Единственное достоинство оператора select - нагладность, при использовании макросов пропадает. Уж лучше Query. |
|
13.02.2013, 14:32 | #10 |
Участник
|
Макрос можно покороче:
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 |
MCTS
|
Еще как вариант можно join из запросов вообще убрать. А есть ли запись в связанной таблице проверять отдельно.
__________________
I could tell you, but then I would have to bill you. |
|
13.02.2013, 14:50 | #12 |
Участник
|
S.Kuskov - согласен не наглядно, сам обычно использую в таких случаях Query, предложил как вариант, т.к. топикстартер отверг все предыдущие варианты. а вот с точки зрения модифицируемости - вполне.
Последний раз редактировалось kair84; 13.02.2013 в 14:54. |
|
13.02.2013, 15:00 | #13 |
Участник
|
Цитата:
Получается, что макросы в принципе нединамические. Как бы макрос не был написан, в конкретном месте основной программы все равно будет либо exists, либо notexists. Цитата:
Похоже, придется использовать вариант X++: if (flag) select... else select... |
|
13.02.2013, 15:01 | #14 |
Участник
|
Цитата:
__________________
// no comments |
|
13.02.2013, 15:19 | #15 |
Участник
|
2 Xardas
в данном случае макроподстановка - это способ уменьшить количество кода PHP код:
|
|
13.02.2013, 15:26 | #16 |
Участник
|
Цитата:
Цитата:
Практика показывает, что зачастую запросы с Exists или not Exists могут вызывать просто дичайшие тормоза (даже по сравнению с вложенными циклами) и приходится сильно мудрить, чтобы этого избежать. Кстати, ведь по описанному Вами условию, Вы имеет "зеркальные" выборки. Это значит, что если Exists будет выполняться быстро, то not Exists неизбежно будет выполняться медленно. Или наоборот. И далеко не факт, что перенесение проверки внутрь цикла существенно повлияет на среднее время выполнения. Повторюсь, это проверить надо. А "в общем случае" рассуждения на подобную тему мало полезны. Именно в силу того, что неизвестны детали задачи. Вполне возможно, что задачу можно решить и без использования Exists просто модифицировав запрос. Однако без знания конкретной постановки задачи заранее сказать нельзя можно это сделать или нет.
__________________
- Может, я как-то неправильно живу?! - Отчего же? Правильно. Только зря... |
|
13.02.2013, 15:58 | #17 |
Administrator
|
Цитата:
Проверял на АХ 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 |
Участник
|
Нет. Не факт Я же говорю, когда речь идет об exist, то все надо проверять экспериментально. Практический результат (скорость выполнения) - слабо предсказуем "теоретическими" рассуждениями.
Тут "фишка" в том, что физически на MS SQL сервере выполняется не "голый" запрос, а запрос "обернутый" в курсор (DECLARE CURSOR ... FOR). Как следствие, планы выполнения "голого" запроса и курсора могут существенно отличаться. Однако здесь ключевое слово "могут". Могут отличаться, а могут и не отличаться. Зависит от кучи условий, не всеми из которых можно управлять. Лично я "напоролся" на подобные различия именно в запросах с Exists. В запросах, где exists отсутствует я подобных различий не наблюдал. Отсюда и повышенная настороженность к подобным запросам.
__________________
- Может, я как-то неправильно живу?! - Отчего же? Правильно. Только зря... |
|
13.02.2013, 17:17 | #19 |
Участник
|
|
|
13.02.2013, 20:46 | #20 |
Участник
|
Цитата:
Сообщение от Xardas
Имеется класс с большим количеством запросов вида
X++: select tbl1 exists join tbl2 where tbl2.field1 == tbl1.field1 Не стоит так делать. Тут уже писали, наиболее нормальный вариант, позволяющий менять тип join'а во время выполнения, - это переписать код на Query'ках. Решать проблему copy-paste'ом - все равно, что заметать сор под половик в надежде, что убирать его придется кому-то другому; это непрофессионально, в конце концов |
|
|
За это сообщение автора поблагодарили: S.Kuskov (1). |
|
|