|
10.03.2017, 15:43 | #1 |
Участник
|
Поле DataAreaID в индексах SQL Server
Dynamics AX 2009
SQL Server 2008 R2 Возникли разногласия при оптимизации запроса на SQL Server по поводу того можно ли (в качестве исключения для особо критичных задач) перемещать поле DataAreaID на другие позиции в индексе средствами SQL Server, как неселективное? Тестирование в рамках SQL показывает значительный прирост производительности. Проблема в том, что при обновлении Аксапты, она вернет все на круги своя. Как лучше поступить в этом случае? Буду признателен за помощь. |
|
10.03.2017, 16:06 | #2 |
Участник
|
В АХ АОТ в описание индекса вставляете вручную (не перетаскиванием) поле DataAreaId и позиционируете его как вам нравится. Ну и синхронизация соответственно.
|
|
|
За это сообщение автора поблагодарили: VORP (2). |
10.03.2017, 16:11 | #3 |
Участник
|
по поводу его позиции есть какие-то противопоказания?
|
|
10.03.2017, 16:13 | #4 |
Участник
|
|
|
10.03.2017, 16:27 | #5 |
Модератор
|
Скажите им, что фикс для parameter sniffing для AX 2009 тоже есть
__________________
-ТСЯ или -ТЬСЯ ? |
|
10.03.2017, 16:29 | #6 |
Участник
|
Есть стандартные таблицы, у которых поле dataAreaId в индексе идет не первым, например SpecTrans, поэтому особых противопоказаний нет, есть индивидуальная не переносимость
Если вы меняете какой-либо из существующих индексов, то лучше пообщаться с людьми, которые могут посмотреть в приложении, не будет ли печальных последствий в других местах.
__________________
Sergey Nefedov |
|
10.03.2017, 16:52 | #7 |
Участник
|
Основное противопоказание, на мой взгляд, это кластерные индексы, т.к. многие грид-формы в АХ выдают информацию без каких-либо фильтров, кроме скрытого фильтра по компании (DataAreaId) и если это поле утащить с первой позиции, то в них могут начаться тормоза.
|
|
10.03.2017, 19:54 | #8 |
Участник
|
"Вот так и рождаются не здоровые сенсации" (с)
Ни числа используемых компаний в AX, ни оптимизируемого запроса, ни объема данных в соотв. табличках.. в этом случае действительно лучше ничего не трогать |
|
|
За это сообщение автора поблагодарили: Vadik (1). |
12.03.2017, 16:23 | #9 |
Участник
|
можно пойти немного другим путем - вместо изменения существующего индекса добавить еще один с тем-же набором, но другим порядком полей. И если оригинальный индекс перестал использоваться и планы исполнения стали использовать только новый, то можно смело менять исходный. Если нет - нужно искать, где он еще используется.
|
|
13.03.2017, 09:41 | #10 |
Участник
|
Цитата:
На данный момент одна компания, но, возможно, будет еще одна. Запрос следующего вида: Код: SELECT SUM(A.POSTEDQTY),SUM(A.POSTEDVALUE),SUM(A.PHYSICALVALUE),SUM(A.DEDUCTED),SUM(A.RECEIVED),SUM(A.RESERVPHYSICAL),SUM(A.RESERVORDERED),SUM(A.REGISTERED),SUM(A.PICKED),SUM(A.ONORDER),SUM(A.ORDERED),SUM(A.ARRIVED),SUM(A.QUOTATIONRECEIPT),SUM(A.QUOTATIONISSUE),SUM(A.AVAILPHYSICAL),SUM(A.AVAILORDERED),SUM(A.PHYSICALINVENT) FROM INVENTSUM A WHERE ((A.DATAAREAID=@P1) AND -- поменять местами поля ((A.ITEMID =@P2) AND (A.CLOSED=@P3))) AND -- Вопрос: почему не используется индекс ECC_FinDimIdx? EXISTS (SELECT 'x' FROM INVENTDIM B with(index(I_698ECC_FINDIMIDX)) WHERE ((B.DATAAREAID=@P4) AND ((((((B.INVENTDIMID=A.INVENTDIMID) AND (B.INVENTSIZEID =@P5)) AND (B.INVENTCOLORID =@P6)) AND (B.INVENTLOCATIONID =@P7)) AND (B.INVENTBATCHID =@P8)) AND (B.INVENTGTDID_RU =@P9)))) |
|
13.03.2017, 11:34 | #11 |
Участник
|
Цитата:
-- Вопрос: почему не используется индекс ECC_FinDimIdx?
Кроме того, при оптимизации запросов следует учитывать тот факт, что Axapta обращается к данным SQL не прямыми запросами, а через "обертку" в виде курсоров. exec sp_cursoropen exec sp_cursorfetch exec sp_cursorclose Как следствие, план выполнения запросов "внутри" курсоров и в "прямых" запросах может очень сильно отличаться, хотя, казалось бы, запрос один и тот же. Подробности можете посмотреть в этой теме Проблемы с Exists Join Вкратце, попробуйте заменить Exists на Inner Join. Поскольку у Вас связь InventSum и InventDim, то в данном случае - это будет корректная замена. И уберите подсказку оптимизатору для индекса
__________________
- Может, я как-то неправильно живу?! - Отчего же? Правильно. Только зря... |
|
13.03.2017, 12:25 | #12 |
Участник
|
Цитата:
Сообщение от Владимир Максимов
Почему не работает подсказка оптимизатору - не знаю. Может, физически нет такого индекса. Судя по префиксу - это какая-то кастомизация. Хотя для Axapta использование подсказок оптимизатору - порочная практика, которая не уменьшает, а увеличивает количество проблем.
Кроме того, при оптимизации запросов следует учитывать тот факт, что Axapta обращается к данным SQL не прямыми запросами, а через "обертку" в виде курсоров. exec sp_cursoropen exec sp_cursorfetch exec sp_cursorclose Как следствие, план выполнения запросов "внутри" курсоров и в "прямых" запросах может очень сильно отличаться, хотя, казалось бы, запрос один и тот же. Подробности можете посмотреть в этой теме Проблемы с Exists Join Вкратце, попробуйте заменить Exists на Inner Join. Поскольку у Вас связь InventSum и InventDim, то в данном случае - это будет корректная замена. И уберите подсказку оптимизатору для индекса На тестовой системе я все это сделал, но в продакшн это не хотят пускать, прикрываясь тем, что поле DataAreaID определяет рамки компании и всегда ставится аксаптой на первое место. |
|
13.03.2017, 13:37 | #13 |
Участник
|
Цитата:
Это все приведет к увеличению кол-ва расщеплений этих страниц при обновлении-вставке данных(а для InventSum это критично), что в конечном итоге потенциально замедлит всю систему. так что вполне аргументировано не дают переносить |
|
13.03.2017, 13:42 | #14 |
Участник
|
Цитата:
Сообщение от trud
если планы одинаковые, то порядок то тут не причем. просто ваш результирующий индекс по видимому имеет другой Fill factor(т.е. получается страницы расположены более плотно раз кол-во логических чтений меньше - тут я подразумеваю что дефрагментацию вы выполнили перед тестом).
Это все приведет к увеличению кол-ва расщеплений этих страниц при обновлении-вставке данных(а для InventSum это критично), что в конечном итоге потенциально замедлит всю систему. так что вполне аргументировано не дают переносить С хинтом соответственно использует. Если поле DataAreaID перенести в конец - оптимизатор хватает наш индекс I_698ECC_FINDIMIDX и количество чтений (и процессорное время) значительно меньше, чем без использования этого индекса (I_698ECC_FINDIMIDX). |
|
13.03.2017, 13:54 | #15 |
Участник
|
А в индексе что за поля? все 5 полей запроса из InventDim?
просто на практике я видел ситуации когда создание подобных индексов приводило к остановкам системы, из за того, что собственно для ряда значений поиск остатков через InventDim приводил к полному скану этой таблицы. т.е. надо проверить что не используются всякие обобщенные партии и гтд |
|
13.03.2017, 12:40 | #16 |
Участник
|
а почему вы хотите его использовать? т.е. для условных значений B.INVENTBATCHID ="без партии и B.INVENTGTDID_RU ="пусто"(т.е. комбинации значений которых много в базе) использование любого индекса по INVENTDIM может привести к большим проблемам. Предположу что SQL рассуждает в таком же духе, раз автоматом не использует индекс
|
|
13.03.2017, 15:23 | #17 |
Участник
|
Извините, а Вы план чего показываете? Выполнения "чистого" запроса или курсора? Вам надо проверять план выполнения вот такой конструкции
Код: declare @P1 nvarchar(3) = N'dat', @P2 nvarchar(20) = N'123456', @P3 int = 0, @P4 nvarchar(3) = N'dat', @P5 nvarchar(20) = N'12345', @P6 nvarchar(20) = N'12345', @P7 nvarchar(20) = N'12345', @P8 nvarchar(20) = N'12345', @P9 nvarchar(20) = N'12345' DECLARE Test CURSOR FOR SELECT SUM(A.POSTEDQTY), SUM(A.POSTEDVALUE), SUM(A.PHYSICALVALUE), SUM(A.DEDUCTED), SUM(A.RECEIVED), SUM(A.RESERVPHYSICAL), SUM(A.RESERVORDERED), SUM(A.REGISTERED), SUM(A.PICKED), SUM(A.ONORDER), SUM(A.ORDERED), SUM(A.ARRIVED), SUM(A.QUOTATIONRECEIPT), SUM(A.QUOTATIONISSUE), SUM(A.AVAILPHYSICAL), SUM(A.AVAILORDERED), SUM(A.PHYSICALINVENT) FROM INVENTSUM A WHERE A.DATAAREAID=@P1 AND A.ITEMID =@P2 AND A.CLOSED=@P3 AND EXISTS (SELECT 'x' FROM INVENTDIM B WHERE B.DATAAREAID=@P4 AND B.INVENTDIMID=A.INVENTDIMID AND B.INVENTSIZEID =@P5 AND B.INVENTCOLORID =@P6 AND B.INVENTLOCATIONID =@P7 AND B.INVENTBATCHID =@P8 AND B.INVENTGTDID_RU =@P9) open test fetch test -- Вот на этой команде план смотреть close test deallocate test Затем сравните план выполнения, если заменить Exists на Inner Join Для целей сравнения запишите 2 запроса рядом в одном Query. Ну, т.е. как-то так Код: DECLARE Test CURSOR FOR SELECT ... FROM InventSum Where Exists(...) DECLARE Test2 CURSOR FOR SELECT ... FROM InventSum INNER JOIN InventDim (...) open test open test2 fetch test -- Вот на этой команде план смотреть fetch test2 -- Вот на этой команде план смотреть PPS: Напомню, что план выполнения запроса с Exists существенно зависит от объема данных. Поэтому Вы можете получить разные планы выполнения на тестовых данных и на рабочих, если на тесте данных немного
__________________
- Может, я как-то неправильно живу?! - Отчего же? Правильно. Только зря... Последний раз редактировалось Владимир Максимов; 13.03.2017 в 15:32. |
|
|
За это сообщение автора поблагодарили: alex55 (1). |
13.03.2017, 17:03 | #18 |
Участник
|
Цитата:
Сообщение от Владимир Максимов
Извините, а Вы план чего показываете? Выполнения "чистого" запроса или курсора? Вам надо проверять план выполнения вот такой конструкции
Код: declare @P1 nvarchar(3) = N'dat', @P2 nvarchar(20) = N'123456', @P3 int = 0, @P4 nvarchar(3) = N'dat', @P5 nvarchar(20) = N'12345', @P6 nvarchar(20) = N'12345', @P7 nvarchar(20) = N'12345', @P8 nvarchar(20) = N'12345', @P9 nvarchar(20) = N'12345' DECLARE Test CURSOR FOR SELECT SUM(A.POSTEDQTY), SUM(A.POSTEDVALUE), SUM(A.PHYSICALVALUE), SUM(A.DEDUCTED), SUM(A.RECEIVED), SUM(A.RESERVPHYSICAL), SUM(A.RESERVORDERED), SUM(A.REGISTERED), SUM(A.PICKED), SUM(A.ONORDER), SUM(A.ORDERED), SUM(A.ARRIVED), SUM(A.QUOTATIONRECEIPT), SUM(A.QUOTATIONISSUE), SUM(A.AVAILPHYSICAL), SUM(A.AVAILORDERED), SUM(A.PHYSICALINVENT) FROM INVENTSUM A WHERE A.DATAAREAID=@P1 AND A.ITEMID =@P2 AND A.CLOSED=@P3 AND EXISTS (SELECT 'x' FROM INVENTDIM B WHERE B.DATAAREAID=@P4 AND B.INVENTDIMID=A.INVENTDIMID AND B.INVENTSIZEID =@P5 AND B.INVENTCOLORID =@P6 AND B.INVENTLOCATIONID =@P7 AND B.INVENTBATCHID =@P8 AND B.INVENTGTDID_RU =@P9) open test fetch test -- Вот на этой команде план смотреть close test deallocate test Затем сравните план выполнения, если заменить Exists на Inner Join Для целей сравнения запишите 2 запроса рядом в одном Query. Ну, т.е. как-то так Код: DECLARE Test CURSOR FOR SELECT ... FROM InventSum Where Exists(...) DECLARE Test2 CURSOR FOR SELECT ... FROM InventSum INNER JOIN InventDim (...) open test open test2 fetch test -- Вот на этой команде план смотреть fetch test2 -- Вот на этой команде план смотреть PPS: Напомню, что план выполнения запроса с Exists существенно зависит от объема данных. Поэтому Вы можете получить разные планы выполнения на тестовых данных и на рабочих, если на тесте данных немного |
|
Теги |
axapta, dynamics ax, sql server, tuning |
|
|