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 สามารถใช้สิ่งที่ไม่ตรงกันได้จะสามารถปรับปรุง I / O ได้อย่างมาก

จำนวนแถวโดยประมาณระหว่าง 2 แผนปิดเช่นกัน ในแผนของคุณด้วยเคอร์เซอร์คุณมีจำนวนแถวโดยประมาณจากค่าความสัมพันธ์ภายนอกที่ 11 ในแผนของคุณโดยไม่มีเคอร์เซอร์คุณจะมีจำนวนแถวโดยประมาณและแท้จริงประมาณ 200K หากบันทึก 200K ของคุณไปสู่ผู้ดำเนินการสปูลนั้นอาจเจ็บปวด

ตัวดำเนินการทั้งหมดมีการประเมินต่างกันอย่างดุเดือด (เล็กกว่ามากในแผนพร้อมเคอร์เซอร์) ดังนั้นอาจมีการรวบรวมแผนของคุณและแคชด้วยค่าพารามิเตอร์ที่แตกต่างจากที่คุณใช้ในแบบสอบถามโดยไม่มีเคอร์เซอร์ (รู้จักกันในชื่อการดมกลิ่นพารามิเตอร์ )

นอกจากนี้ยังมีตัวเลือกที่แปลกมากในดัชนีการค้นหา + ค้นหาคีย์บนตารางการประดิษฐ์ แผนใช้ typeIdx จากนั้นทำการค้นหาคีย์ไปยังดัชนีคลัสเตอร์ (itemidx) ถ้าค่าประมาณของคุณอยู่ที่นั่นและ SQL Server ต้องทำการค้นหาคีย์จำนวนมากที่สามารถอธิบาย IO ได้มากมายเช่นกัน ฉันไม่คุ้นเคยกับ stopidx ที่คุณมีในแผนของคุณโดยไม่มีเคอร์เซอร์ แต่ดูเหมือนว่ามันครอบคลุมดังนั้นอาจเป็นตัวเลือกที่ดีกว่าสำหรับพารามิเตอร์ที่คุณให้ ฉันคิดว่ามันเลือก typeidx เพราะแคบกว่า แต่อาจเป็นเพราะค่าเวลาในการรวบรวมต่างจากที่คุณให้ไว้กับการประมวลผลที่มีปัญหา

ในระยะสั้นฉันจะลบการตั้งค่าสำหรับแบบสอบถามนี้ใน AX ดังนั้นมันจึงสร้างแผนที่มีค่าจริงดังนั้นมันจึงเลือกดัชนี "ดีกว่า" ดังที่เห็นได้จากแผน (และเวลาดำเนินการ) ใน SSMS สิ่งนี้จะอนุญาตให้ SQL Server ใช้ดัชนีที่กรองแล้ว ในการดำเนินการดังกล่าวให้นักพัฒนาเพิ่มforceliteralsคำหลักลงในรหัสแอปพลิเคชันซึ่งดำเนินการค้นหานี้และดูว่าเกิดอะไรขึ้น

นั่นอาจจะทำให้คุณมีแบบสอบถามที่ใช้เวลา 30 วินาที (คล้ายกับสิ่งที่คุณมีใน SSMS) แต่นั่นเป็นเพียงเรื่องของการปรับแต่ง มีคำเตือนดัชนีหายไปในแผนของคุณและฉันคิดว่าดัชนีใน ecoresproductordernum.sge สามารถช่วยยกตัวอย่างได้ แต่ฉันไม่รู้ตารางเหล่านั้นและคิดว่าพวกเขาถูกเพิ่มโดยการปรับแต่ง หลักการปรับทั่วไปจะช่วยได้ที่นี่ แต่อาจจะกว้างเกินไปสำหรับคำตอบนี้ (ครอบคลุมดัชนี, ... )


นี่เป็นการแก้ไขปัญหาของฉัน เราจริงๆแล้วมีสองปัญหา: พารามิเตอร์ดมกลิ่นและ filterd ก่อให้เกิด เราพลาดข้ามความสัมพันธ์บางส่วนใน AX ดังนั้นแอปพลิเคชันจึงสร้างประโยคแปลก "ใน" สำหรับ DirPartyTable ตอนจบของเรื่องนี้ไม่เคยข้ามความสัมพันธ์ตาราง :)
ฮันส์เวเดอร์
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.