sp_cursorprepexec викликає 53 мільйони читань?


9

Ми запускаємо установку Dynamics AX 2012 за допомогою SQL Server 2012. Я знаю, що курсори більше не повинні використовуватися, але AX використовує його, і ми не можемо змінити цю поведінку, тому нам доведеться з нею працювати.

Сьогодні я зловив дуже поганий запит із понад 53 мільйонами читань та часом виконання понад 20 хвилин.

Я знайшов цей запит через наш інструмент моніторингу SentryOne.

declare @p1 int
set @p1=1073773227
declare @p2 int
set @p2=180158805
declare @p5 int
set @p5=16
declare @p6 int
set @p6=1
declare @p7 int
set @p7=2
exec sp_cursorprepexec @p1 output,@p2 output,N'@P1 bigint,@P2 nvarchar(5),@P3 bigint,@P4 nvarchar(8),@P5 bigint,@P6 bigint,@P7 bigint,@P8 bigint,@P9 bigint,@P10 bigint,@P11 bigint,@P12 bigint,@P13 bigint,@P14 bigint,@P15 bigint,@P16 bigint,@P17 bigint,@P18 bigint,@P19 nvarchar(5),@P20 bigint,@P21 bigint,@P22 bigint,@P23 bigint,@P24 bigint',N'SELECT T1.PRODUCT,T1.EXTERNALVENDPARTY,T1.LIFECYCLESTATUS,T1.RECID,T2.ECORESPRODUCT,T2.ECORESDISTINCTPRODUCTVARIANT,T2.SGE,T2.ECORESREFORDERNUM,T2.ORDERNUM,T2.RECID,T3.ECORESREFORDERNUM,T3.NAME1,T3.NAME2,T3.NAME3,T3.RECID,T4.ECORESPRODUCT,T4.EXTERNALITEMID,T4.ECORESDISTINCTPRODUCTVARIANT,T4.RECID,T5.RECID,T5.PERSON,T6.RECID,T6.NAME,T6.INSTANCERELATIONTYPE,T7.RECID,T7.NAME,T7.INSTANCERELATIONTYPE,T8.PARTY,T8.ACCOUNTNUM,T8.RECID,T9.RECID,T9.DISPLAYPRODUCTNUMBER,T9.INSTANCERELATIONTYPE,T10.PRODUCT,T10.CATEGORY,T10.RECID,T11.RECID,T11.CODE,T11.NAME,T11.INSTANCERELATIONTYPE FROM INVENTTABLE T1 CROSS JOIN ECORESPRODUCTORDERNUM T2 CROSS JOIN ECORESPRODUCTORDERNUMTRANSLATION T3 LEFT OUTER JOIN VENDEXTERNALITEM T4 ON ((T4.PARTITION=5637144576) AND ((T2.ECORESPRODUCT=T4.ECORESPRODUCT) AND (T4.ECORESDISTINCTPRODUCTVARIANT=@P1))) CROSS JOIN HCMWORKER T5 CROSS JOIN DIRPARTYTABLE T6 CROSS JOIN DIRPARTYTABLE T7 CROSS JOIN VENDTABLE T8 CROSS JOIN ECORESPRODUCT T9 CROSS JOIN ECORESPRODUCTCATEGORY T10 CROSS JOIN ECORESCATEGORY T11 WHERE (((T1.PARTITION=5637144576) AND (T1.DATAAREAID=N''087'')) AND (T1.DATAAREAID=@P2)) AND ((T2.PARTITION=5637144576) AND ((T2.ECORESPRODUCT=T1.PRODUCT) AND (T2.SGE=@P3))) AND ((T3.PARTITION=5637144576) AND ((T3.ECORESREFORDERNUM=T2.ECORESREFORDERNUM) AND (T3.LANGUAGEID=@P4))) AND ((T5.PARTITION=5637144576) AND (T5.RECID=T2.PRODUCTMANAGER)) AND (((T6.PARTITION=5637144576) AND (T6.INSTANCERELATIONTYPE IN (@P5,@P6,@P7,@P8,@P9,@P10,@P11) )) AND (T6.RECID=T5.PERSON)) AND (((T7.PARTITION=5637144576) AND (T7.INSTANCERELATIONTYPE IN (@P12,@P13,@P14,@P15,@P16,@P17,@P18) )) AND (T1.EXTERNALVENDPARTY=T7.RECID)) AND (((T8.PARTITION=5637144576) AND (T8.DATAAREAID=N''087'')) AND ((T7.RECID=T8.PARTY) AND (T8.DATAAREAID=@P19))) AND (((T9.PARTITION=5637144576) AND (T9.INSTANCERELATIONTYPE IN (@P20,@P21,@P22) )) AND (T9.RECID=T1.PRODUCT)) AND ((T10.PARTITION=5637144576) AND (T10.PRODUCT=T9.RECID)) AND (((T11.PARTITION=5637144576) AND (T11.INSTANCERELATIONTYPE IN (@P23,@P24) )) AND (T11.RECID=T10.CATEGORY))',@p5 output,@p6 output,@p7 output,0,N'087',5637146082,N'de',41,2303,2377,2975,2978,5329,6886,41,2303,2377,2975,2978,5329,6886,N'087',3265,3266,3267,2665,4423
select @p1, @p2, @p5, @p6, @p7

Перше, що я помітив, це те, що цей запит використовував курсор. З цікавості я скопіював заяву та виконав її в «Майстерні управління» без курсору (я повинен визнати, що я замінив параметри запиту, щоб я міг його запустити). У SSMS запит завершився за 30 секунд. Не дуже швидко, але все ж швидше, ніж курсорна альтернатива.

Тут я надаю вам обидва плани:

План без курсору все ще дуже поганий план, але він набагато кращий. Моє запитання тут: Чи можете мені хтось пояснити, чому для курсової версії потрібно 53 мільйони прочитаних?

Статистика для запиту курсором:

Duration    CPU         Reads       Writes  Est Rows    Actual Rows
1.396.212   1.379.157   53.270.895  3.878   30          2

Статистика для запиту без курсору:

Duration    CPU         Reads       Writes  Est Rows    Actual Rows
23.337      1.703       665.113     13      4.287       34.813

Це здається дивним отримати 34 813 рядків замість 2; але я впевнений, що я заповнив правильні параметри. Я подумав, що це, можливо, смішна примха від SQL Sentry, оскільки я просто скопіював статистику звідти.

Сподіваюся, я міг би надати всю необхідну для вас інформацію. Крім того, якщо хтось має хороші читання, то краще розумійте курсори, що було б чудово.

Відповіді:


10

Перш за все, мене дивує, що фактична кількість рядків для обох запитів у SQL Sentry не є більш-менш однаковою.

Друге. Важко сказати, наскільки правильні ваші оцінки в плані за допомогою курсору без фактичного плану, але деякі речі мені виділяються. (PS: див. Мою відповідь тут, щоб отримати фактичний план).

Це, як сказано, є кілька речей, які можна відзначити з вашої прогнозованої програми.

Існує попередження про невідповідні індекси через параметризацію. Якщо видалити параметризацію, щоб SQL Server міг використовувати ті, що не мають відповідних можливостей, це значно покращить введення / виведення.

Орієнтовна кількість рядків між двома планами теж відменена. У вашому плані з курсором у вас є приблизна кількість рядків від vendexternalitem 11. У вашому плані без курсору у вас є приблизна і фактична кількість рядків майже 200K. Якщо ваші записи 200K дійсно потрапляють до цього оператора котушки, це може бути боляче.

Усі оператори мають неоднаково різні оцінки (набагато менші в плані з курсором), тому, можливо, ваш план був складений та кешований з іншими значеннями параметрів, ніж ви використовуєте в запиті без курсору. (відомий як нюхання параметрів )

Існує також дуже дивний вибір у пошуку індексу + пошук ключів на таблиці вигадок. План використовує typeIdx, а потім здійснює пошук ключів до кластерного індексу (itemidx). Якщо ваші оцінки там не вдається, і SQL Server повинен зробити багато ключових пошукових запитів, які також можуть пояснити багато IO. Я не знайомий зі стопідкс у вашому плані без курсору, але він виглядає так, ніби він покриває, так що, мабуть, кращий вибір для наданих вами параметрів. Я думаю, що він вибрав typeidx, тому що він набагато вужчий, але це може бути пов'язано з різними значеннями часу компіляції, ніж ви надаєте з проблемним виконанням.

Коротше кажучи, я видалив би параметризацію для цього запиту в AX, щоб він генерував план з фактичними значеннями, щоб він вибирав "кращі" індекси, як свідчить план (і час виконання) в SSMS. Це також дозволило б SQL Server використовувати відфільтровані індекси. Для цього потрібно, щоб розробник додав forceliteralsключове слово в код програми, де виконується цей запит, і побачити, що відбувається.

Це, ймовірно, все ще залишить вас із запитом, який займає 30 секунд (подібний до того, що у вас в SSMS), але це лише питання налаштування. У ваших планах відсутні попередження щодо індексу, і я думаю, що індекс на ecoresproductordernum.sge може допомогти, наприклад, але я не знаю цих таблиць і думаю, що вони додаються за допомогою налаштувань. Тут допоможуть загальні принципи настройки, але це може бути занадто широким для цієї відповіді (охоплюючи індекси, ...)


Це вирішило мою проблему. Насправді у нас були дві проблеми: обнюхування параметрів та відфільтровані індизи. Ми пропустили деякі відносини в AX, тому додаток створило цей дивний пункт "в" для DirPartyTable. Кінець історії: ніколи не пропускайте столові відносини :)
Ганс Вейдер
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.