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

 
 
Опции темы Поиск в этой теме Опции просмотра
Старый 10.01.2008, 12:10   #1  
oleg_e is offline
oleg_e
Участник
 
71 / 10 (1) +
Регистрация: 12.01.2006
Адрес: Moscow
:( Оптимизация запроса
День добрый! Не подскажут ли знатоки, есть ли альтернатива по тяжелым запросам использующие exists join? Есть следующий запрос (см.ниже), использующий тяжелые таблицы (inventtrans>4 млн строк, inventdim>300 тыс, табл. А и B >500 тыс). Сейчас время отчета с использованием этого запроса более 40 мин (при выбранном периоде 1 мес)
Можно ли модифицироать запрос? Будем считать, что индексы расставлены.
Использование forcenestedloop forceselectorder ненамного сократило время.
Прошу прощения, на неформатированность запроса

while select inventTrans
where ((inventTrans.TransType == InventTransType::Purch) || (inventTrans.TransType == InventTransType::Sales))
&& (includeEstimated || ( ! includeEstimated &&
((inventTrans.StatusReceipt == StatusReceipt::None && inventTrans.StatusIssue == StatusIssue::Sold) ||
(inventTrans.StatusReceipt == StatusReceipt::Purchased && inventTrans.StatusIssue == StatusIssue::None))))
&& (inventTrans.DateFinancial
&& inventTrans.DateFinancial >= dateFrom && inventTrans.DateFinancial <= dateTo) ||
(!inventTrans.DateFinancial
&& inventTrans.DateExpected >= dateFrom && inventTrans.DateExpected <= dateTo))
join [fields] from inventTable
where inventTable.ItemId == inventTrans.ItemId &&
inventTable.ItemType != .....
join [fields] from inventDim
where inventDim.InventDimId == inventTrans.InventDimId
&& (.........)
exists join [fields] from A
where A.[X] == inventDim.[Y]
join B
where B.InventDimId == A.InventDimId
&& ((B.DateFinancial && B.DateFinancial >= dateFrom
&& B.DateFinancial <= dateTo) ||
( !B.DateFinancial && B.DateExpected >= dateFrom && B.DateExpected <= dateTo))

Последний раз редактировалось oleg_e; 31.01.2008 в 12:59.
Старый 10.01.2008, 12:39   #2  
Zuzaz is offline
Zuzaz
Участник
 
119 / 18 (1) ++
Регистрация: 22.09.2006
Как только в условии запроса появляется "или", про индекс можно забыть. Постарайтесь перестроить условие запроса, чтобы "или" не было вообще, либо они были как можно более ниже в условии.
Старый 10.01.2008, 12:54   #3  
oleg_e is offline
oleg_e
Участник
 
71 / 10 (1) +
Регистрация: 12.01.2006
Адрес: Moscow
Без "ИЛИ" никак нельзя...
Старый 10.01.2008, 13:22   #4  
belugin is offline
belugin
Участник
Аватар для belugin
Сотрудники Microsoft Dynamics
Лучший по профессии 2017
Лучший по профессии 2015
Лучший по профессии 2014
Лучший по профессии 2011
Лучший по профессии 2009
 
4,622 / 2925 (107) +++++++++
Регистрация: 16.01.2004
Записей в блоге: 5
1. Что говорит план запроса?
2. Какое наиболее селективное условие запроса?
Старый 10.01.2008, 13:47   #5  
ansoft is offline
ansoft
Участник
Аватар для ansoft
 
123 / 37 (2) +++
Регистрация: 20.10.2005
Что если перестроить запрос так:

while select [fields] from inventTable
where inventTable.ItemType != .....

join [fields] from inventTrans
where inventTrans.ItemId == inventTable.ItemId &&
((inventTrans.TransType == InventTransType::Purch) || (inventTrans.TransType == InventTransType::Sales))
&& (includeEstimated || ( ! includeEstimated &&
((inventTrans.StatusReceipt == StatusReceipt::None && inventTrans.StatusIssue == StatusIssue::Sold) ||
(inventTrans.StatusReceipt == StatusReceipt::Purchased && inventTrans.StatusIssue == StatusIssue::None))))
&& (inventTrans.DateFinancial
&& inventTrans.DateFinancial >= dateFrom && inventTrans.DateFinancial <= dateTo) ||
(!inventTrans.DateFinancial
&& inventTrans.DateExpected >= dateFrom && inventTrans.DateExpected <= dateTo))

join [fields] from inventDim
where inventDim.InventDimId == inventTrans.InventDimId
&& (.........)

exists join [fields] from A
where A.[X] == inventDim.[Y]

join B
where B.InventDimId == A.InventDimId
&& ((B.DateFinancial && B.DateFinancial >= dateFrom
&& B.DateFinancial <= dateTo) ||
( !B.DateFinancial && B.DateExpected >= dateFrom && B.DateExpected <= dateTo))

Есть мысль, что это сократит "терзания" InventTrans (+InventDim) и будет быстрее...
Старый 10.01.2008, 13:59   #6  
oleg_e is offline
oleg_e
Участник
 
71 / 10 (1) +
Регистрация: 12.01.2006
Адрес: Moscow
спасибо, попробую и скажу
Старый 10.01.2008, 14:25   #7  
Jabberwocky is offline
Jabberwocky
Microsoft Dynamics
Аватар для Jabberwocky
Сотрудники Microsoft Dynamics
 
274 / 307 (11) ++++++
Регистрация: 02.09.2005
Адрес: Москва
Цитата:
Сообщение от ansoft Посмотреть сообщение
Что если перестроить запрос так:

while select [fields] from inventTable
where inventTable.ItemType != .....
В данном случае необходимо также использовать forcenestedloop forceselectorder, чтобы цикл join'a начинался именно с InventTable. И еще попробуйте соптимизировать критерии выборки, например условие:

inventTrans.StatusReceipt == StatusReceipt::None && inventTrans.StatusIssue == StatusIssue::Sold

эквивалентно:

inventTrans.StatusIssue == StatusIssue::Sold ,

т.к. StatusReceipt и StatusIssue одновременно никогда не бывают не-None.

Аналогично,
inventTrans.DateFinancial
&& inventTrans.DateFinancial >= dateFrom && inventTrans.DateFinancial <= dateTo

проверка на непустую дату inventTrans.DateFinancial явно избыточна, если dateFrom и dateTo заведомо не пустые и т.д.
__________________
You should use Bing before asking dumb questions.
Старый 10.01.2008, 14:58   #8  
Alexius is offline
Alexius
Участник
Аватар для Alexius
 
461 / 248 (9) ++++++
Регистрация: 13.12.2001
;)
Цитата:
Сообщение от oleg_e Посмотреть сообщение
Будем считать, что индексы расставлены.
А можно полюбопытствовать, какие ?

1. Рекомендую избавится от использования в условии запроса переменной includeEstimated, использовав несколько специализированных запросов и при необходимости подпроцедуру для тела цикла
2. Вместо конструкций вида
Цитата:
Сообщение от oleg_e Посмотреть сообщение
((inventTrans.StatusReceipt == StatusReceipt::None && inventTrans.StatusIssue == StatusIssue::Sold) ||
(inventTrans.StatusReceipt == StatusReceipt::Purchased && inventTrans.StatusIssue == StatusIssue::None))
в Аксапте лучше использовать

(inventTrans.StatusReceipt == StatusReceipt::None || inventTrans.StatusReceipt == StatusReceipt::Purchased) &&
(inventTrans.StatusIssue == StatusIssue::None || inventTrans.StatusIssue == StatusIssue::Sold)

3. Даты тоже можно немного оптимизировать, меняем
Цитата:
Сообщение от oleg_e Посмотреть сообщение
(inventTrans.DateFinancial
&& inventTrans.DateFinancial >= dateFrom && inventTrans.DateFinancial <= dateTo) ||
(!inventTrans.DateFinancial
&& inventTrans.DateExpected >= dateFrom && inventTrans.DateExpected <= dateTo))
на

inventTrans.DateFinancial >= dateFrom
&& (inventTrans.DateFinancial && inventTrans.DateFinancial <= dateTo ||
(!inventTrans.DateFinancial
&& inventTrans.DateExpected >= dateFrom && inventTrans.DateExpected <= dateTo))

PS. А лучше всего поймать этот запрос в MS SQL Profiler и посмотреть его план выполнения
Старый 10.01.2008, 15:23   #9  
Alexius is offline
Alexius
Участник
Аватар для Alexius
 
461 / 248 (9) ++++++
Регистрация: 13.12.2001
4. Если из inventTrans нужны не все поля, то лучше их перечислить в запросе для уменьшения результирующего объема выборки
Старый 10.01.2008, 15:28   #10  
dn is offline
dn
Участник
Самостоятельные клиенты AX
 
486 / 159 (6) ++++++
Регистрация: 26.03.2003
Адрес: Москва
Цитата:
Сообщение от oleg_e Посмотреть сообщение
(inventTrans.DateFinancial
&& inventTrans.DateFinancial >= dateFrom && inventTrans.DateFinancial <= dateTo) ||
(!inventTrans.DateFinancial
&& inventTrans.DateExpected >= dateFrom && inventTrans.Date<= dateTo)
Скорее всего в данном случае вполне можно вместо условия по полям DateFinancial и DateExpected написать условие по одной дате DateStatus. Алгоритм заполнения DateStatus в методе inventTrans.setStatusDate().
Старый 10.01.2008, 16:53   #11  
oleg_e is offline
oleg_e
Участник
 
71 / 10 (1) +
Регистрация: 12.01.2006
Адрес: Moscow
Red face
Спасибо всем. Немного конкретезирую запрос (было до этого абстрактно):

while select inventTrans
where ((inventTrans.TransType == InventTransType::Purch) || (inventTrans.TransType == InventTransType::Sales))
&& (includeEstimated || ( ! includeEstimated &&
((inventTrans.StatusReceipt == StatusReceipt::None && inventTrans.StatusIssue == StatusIssue::Sold) ||
(inventTrans.StatusReceipt == StatusReceipt::Purchased && inventTrans.StatusIssue == StatusIssue::None))))
&& (transByPeriod
&& ((inventTrans.DateFinancial
&& inventTrans.DateFinancial >= dateFrom
&& inventTrans.DateFinancial <= dateTo) ||
( ! inventTrans.DateFinancial
&& inventTrans.DateExpected >= dateFrom
&& inventTrans.DateExpected <= dateTo)) || (!transByPeriod))
join ItemCategoryId from inventTable
where inventTable.ItemId == inventTrans.ItemId &&
inventTable.ItemType != ItemType::.....
join DlvInventTripId from inventDim
where inventDim.InventDimId == inventTrans.InventDimId
&& (( ! tripId && inventDim.DlvInventTripId != "") || (tripId && inventDim.DlvInventTripId == tripId))
exists join DlvInventTripId from inventDimTripByPeriod
where inventDimTripByPeriod.[field] == inventDim.[field]
join inventTransByPeriod
where inventTransByPeriod.InventDimId == inventDimTripByPeriod.InventDimId
&& ((inventTransByPeriod.DateFinancial
&& inventTransByPeriod.DateFinancial >= dateFrom
&& inventTransByPeriod.DateFinancial <= dateTo) ||
( ! inventTransByPeriod.DateFinancial
&& inventTransByPeriod.DateExpected >= dateFrom
&& inventTransByPeriod.DateExpected <= dateTo))

Пояснение к запросу
inventTransByPeriod это inventtrnas
inventDimTripByPeriod это inventDim

признаки (NOYES) для запроса:
includeEstimated,transByPeriod
Старый 10.01.2008, 17:34   #12  
Alexius is offline
Alexius
Участник
Аватар для Alexius
 
461 / 248 (9) ++++++
Регистрация: 13.12.2001
Вторая серия, для начала:

1. Индекс на таблицу inventTrans с 3-мя полями DateFinancial, DateExpected, InventDimId

2. Слегка модифицированный запрос

while select inventTrans
where ((inventTrans.TransType == InventTransType::Purch) || (inventTrans.TransType == InventTransType::Sales))
&& (includeEstimated || ( ! includeEstimated &&
((inventTrans.StatusReceipt == StatusReceipt::None && inventTrans.StatusIssue == StatusIssue::Sold) ||
(inventTrans.StatusReceipt == StatusReceipt::Purchased && inventTrans.StatusIssue == StatusIssue::None))))
&& (transByPeriod
&& ((inventTrans.DateFinancial
&& inventTrans.DateFinancial >= dateFrom
&& inventTrans.DateFinancial <= dateTo) ||
( ! inventTrans.DateFinancial
&& inventTrans.DateExpected >= dateFrom
&& inventTrans.DateExpected <= dateTo)) || (!transByPeriod))
join ItemCategoryId from inventTable
where inventTable.ItemId == inventTrans.ItemId &&
inventTable.ItemType != ItemType::.....
join DlvInventTripId from inventDim
where inventDim.InventDimId == inventTrans.InventDimId
&& (( ! tripId && inventDim.DlvInventTripId != "") || (tripId && inventDim.DlvInventTripId == tripId))
exists join DlvInventTripId from inventDimTripByPeriod
where inventDimTripByPeriod.[field] == inventDim.[field]
join inventTransByPeriod
where inventTransByPeriod.InventDimId == inventDimTripByPeriod.InventDimId
&& inventTransByPeriod.DateFinancial <= dateTo
&& ((inventTransByPeriod.DateFinancial
&& inventTransByPeriod.DateFinancial >= dateFrom) ||
( ! inventTransByPeriod.DateFinancial
&& inventTransByPeriod.DateExpected >= dateFrom
&& inventTransByPeriod.DateExpected <= dateTo))
Старый 10.01.2008, 17:37   #13  
NNB is offline
NNB
Участник
 
103 / 12 (1) ++
Регистрация: 31.08.2006
Что будет если запустить запрос на сервере с помощью скажем E...M...?
Обязательно ли использовать While select?
Старый 10.01.2008, 18:52   #14  
oleg_e is offline
oleg_e
Участник
 
71 / 10 (1) +
Регистрация: 12.01.2006
Адрес: Moscow
Alexius,
а нужно ли в запросе использовать волшебные слова forcenestedloop forceselectorder?
Старый 10.01.2008, 19:13   #15  
Wamr is offline
Wamr
----------------
Лучший по профессии 2014
Лучший по профессии AXAWARD 2013
 
1,737 / 858 (32) +++++++
Регистрация: 15.01.2002
Адрес: Москва
Записей в блоге: 7
Не надо делать таких запросов.
- структура ограничений, а, следовательно, и план исполнения сильно зависят от входных параметров (includeEstimated,transByPeriod, tripId). Такое построение часто приводит к неожиданным зависаниям, даже при малом объеме выбираемых данных.
- разобраться через неделю, что делается в запросе сложно. А чтобы что-то подправить через месяц, придется полдня только вспоминать что же тут понаписано.
Предлагаю использовать queryRun или последовательность select cursor - while cursor - next cursor. И перестраивать запрос в заисимости от входных параметров, а не взрывать мозг SQL-серверу.

Попробуйте сами продумать план запроса. Какие ограничения должны примениться первыми, какие вторыми. Только после этого можно думать о применении "волшебных слов forcenestedloop forceselectorder"

Опишите простыми словами, что же вы тут пытаитесь выбрать.
Старый 11.01.2008, 09:37   #16  
Alexius is offline
Alexius
Участник
Аватар для Alexius
 
461 / 248 (9) ++++++
Регистрация: 13.12.2001
Цитата:
Сообщение от oleg_e Посмотреть сообщение
Alexius,
а нужно ли в запросе использовать волшебные слова forcenestedloop forceselectorder?
Это лучше определить экспериментальным путем. Я воздержусь давать универсальную рекомендацию.
Старый 11.01.2008, 10:22   #17  
NNB is offline
NNB
Участник
 
103 / 12 (1) ++
Регистрация: 31.08.2006
Добрый день
Конкретизирую что написал вчера
Как бы я поступил:
1. Понял бы куда уходит время: на создание курсора или движение по нему
2. Если на создание - то проверил бы наличие индексов на полях связи и ограничениях, запустил бы запрос на SQL сервере и постарался оптимизировать там.
3. Если получилось - то постарался бы перенести это в Axaptу. Если не получилось перенести, то постарался бы использовать хранимую процедуру на сервере. Если на сервере запрос работает долго - значит не повезло. Остается только постараться получать промежуточные данные в пакетном режиме и затем использовать их
4. Если задержка вызвана движением по курсору - то постарался бы обойтись без него

Успехов
Теги
оптимизация, производительность, ax3.0

 

Похожие темы
Тема Автор Раздел Ответов Посл. сообщение
Оптимизация запроса - ranges kashperuk DAX: Программирование 13 31.01.2011 20:19
Изменить план выполнения запроса Sequel DAX: Администрирование 2 29.05.2008 15:46
Быстродействие запроса Antonuch DAX: Программирование 1 25.01.2008 15:58
Опять оптимизация запроса KpecT DAX: Программирование 3 02.11.2007 14:41
Оптимизация запроса Янка DAX: Программирование 1 27.04.2006 08:37

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

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

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