sp_cursorprepexec gây ra 53 triệu lượt đọc?


9

Chúng tôi đang chạy cài đặt Dynamics AX 2012 với SQL Server 2012. Tôi biết rằng không nên sử dụng con trỏ nữa nhưng AX đang sử dụng và chúng tôi không thể thay đổi hành vi này vì vậy chúng tôi phải làm việc với nó.

Hôm nay tôi bắt được một truy vấn rất tệ với hơn 53 triệu lượt đọc và thời gian thực hiện lớn hơn 20 phút.

Tôi đã bắt được truy vấn này thông qua công cụ giám sát SentryOne của chúng tôi.

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

Điều đầu tiên tôi nhận thấy là truy vấn này đã sử dụng một con trỏ. Vì tò mò tôi đã sao chép câu lệnh và thực thi nó trong Management Studio mà không có công cụ con trỏ (tôi phải thừa nhận rằng tôi đã thay thế các tham số cho truy vấn để tôi có thể chạy nó). Trong SSMS, truy vấn kết thúc sau 30 giây. Không nhanh lắm, nhưng vẫn nhanh hơn con trỏ thay thế.

Ở đây tôi cung cấp cho bạn cả hai kế hoạch:

Kế hoạch không có con trỏ vẫn là một kế hoạch rất xấu nhưng tốt hơn nhiều. Câu hỏi của tôi ở đây là: Ai đó có thể vui lòng giải thích cho tôi tại sao phiên bản con trỏ cần 53 triệu lượt đọc không?

Số liệu thống kê cho truy vấn với con trỏ:

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

Số liệu thống kê cho truy vấn không có con trỏ:

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

Có vẻ lạ khi lấy 34.813 hàng thay vì 2; nhưng tôi khá chắc chắn rằng tôi đã điền đúng thông số. Tôi nghĩ rằng đây có thể là một trò hề hài hước từ SQL Sentry vì tôi chỉ sao chép số liệu thống kê từ đó.

Tôi hy vọng tôi có thể cung cấp cho bạn tất cả các thông tin cần thiết cho bạn. Ngoài ra nếu bất cứ ai có một số bài đọc tốt, các con trỏ hiểu rõ hơn sẽ là tuyệt vời.

Câu trả lời:


10

Trước hết, điều làm tôi ngạc nhiên là số lượng hàng thực tế cho cả hai truy vấn từ SQL Sentry không ít nhiều giống nhau.

Thứ hai. Thật khó để nói chính xác các ước tính của bạn trong kế hoạch với một con trỏ không có kế hoạch thực tế nhưng một số điều nổi bật với tôi. (PS: tham khảo câu trả lời của tôi ở đây để có được một kế hoạch thực tế).

Điều đó đang được nói, có một vài điều có thể được ghi nhận từ kế hoạch ước tính của bạn.

Có một cảnh báo về các chỉ số chưa từng có do tham số hóa. Xóa tham số để SQL Server có thể sử dụng những cái chưa từng có có thể cải thiện đáng kể I / O.

Số lượng hàng ước tính giữa 2 kế hoạch cũng bị giảm đáng kể. Trong kế hoạch của bạn với một con trỏ, bạn có số lượng hàng ước tính từ kẻ thù là 11. Trong kế hoạch của bạn không có con trỏ, bạn có số lượng hàng ước tính và thực tế là gần 200K. Nếu hồ sơ 200K của bạn thực sự đi vào toán tử bộ đệm đó có thể gây đau đớn.

Tất cả các toán tử có các ước tính cực kỳ khác nhau (nhỏ hơn nhiều trong kế hoạch với một con trỏ), vì vậy có thể gói của bạn được biên dịch và lưu vào bộ đệm với các giá trị tham số khác với bạn đang sử dụng trong truy vấn không có con trỏ. (được gọi là đánh hơi tham số )

Ngoài ra còn có một lựa chọn rất lạ trong chỉ mục tìm kiếm + tra cứu khóa trên bảng phát minh. Kế hoạch đang sử dụng typeIdx và sau đó thực hiện tra cứu chính cho chỉ mục được nhóm (itemidx). Nếu ước tính của bạn bị tắt và SQL Server phải thực hiện nhiều tra cứu chính có thể giải thích rất nhiều IO. Tôi không quen thuộc với stopidx mà bạn có trong kế hoạch của mình mà không có con trỏ nhưng có vẻ như nó bao phủ nên có lẽ đó là lựa chọn tốt hơn cho các tham số bạn cung cấp. Tôi cho rằng nó đã chọn typeidx vì nó hẹp hơn nhiều nhưng điều đó có thể là do các giá trị thời gian biên dịch khác nhau so với bạn đang cung cấp với việc thực thi có vấn đề.

Nói tóm lại, tôi sẽ xóa tham số cho truy vấn này trong AX để nó tạo ra một kế hoạch với các giá trị thực tế để nó chọn các chỉ mục "tốt hơn" như được chứng minh bằng kế hoạch (và thời gian thực hiện) trong SSMS. Điều này cũng sẽ cho phép SQL Server sử dụng các chỉ mục được lọc. Để làm như vậy, yêu cầu nhà phát triển thêm forceliteralstừ khóa vào mã ứng dụng nơi truy vấn này được thực thi và xem điều gì sẽ xảy ra.

Điều đó có thể vẫn để lại cho bạn một truy vấn mất 30 giây (tương tự như những gì bạn có trong SSMS) nhưng đó chỉ là vấn đề điều chỉnh. Có các cảnh báo chỉ mục bị thiếu trong các kế hoạch của bạn và tôi nghĩ rằng một chỉ mục trên ecoresproductordernum.sge có thể giúp ích nhưng tôi không biết các bảng đó và nghĩ rằng chúng được thêm vào bởi các tùy chỉnh. Nguyên tắc điều chỉnh chung sẽ giúp ích ở đây nhưng điều đó có thể quá rộng cho câu trả lời này (bao gồm các chỉ mục, ...)


Điều này đã giải quyết vấn đề của tôi. Chúng tôi thực tế đã có hai vấn đề: Thông số đánh hơi và bộ lọc kích thước. Chúng tôi đã bỏ qua một số mối quan hệ trong AX để ứng dụng tạo ra mệnh đề "in" kỳ lạ này cho DirPartyTable. Kết thúc câu chuyện: không bao giờ bỏ qua các mối quan hệ bảng :)
Hans Vader
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.