เหตุใดตารางที่ได้รับนี้จึงปรับปรุงประสิทธิภาพ


18

ฉันมีแบบสอบถามซึ่งใช้สตริง json เป็นพารามิเตอร์ json เป็นอาร์เรย์ของคู่ละติจูดและลองจิจูด ตัวอย่างอินพุตอาจเป็นดังต่อไปนี้

declare @json nvarchar(max)= N'[[40.7592024,-73.9771259],[40.7126492,-74.0120867]
,[41.8662374,-87.6908788],[37.784873,-122.4056546]]';

มันเรียก TVF ที่คำนวณจำนวนจุดที่น่าสนใจรอบ ๆ จุดทางภูมิศาสตร์ที่ระยะ 1,3,5,10 ไมล์

create or alter function [dbo].[fn_poi_in_dist](@geo geography)
returns table
with schemabinding as
return 
select count_1  = sum(iif(LatLong.STDistance(@geo) <= 1609.344e * 1,1,0e))
      ,count_3  = sum(iif(LatLong.STDistance(@geo) <= 1609.344e * 3,1,0e))
      ,count_5  = sum(iif(LatLong.STDistance(@geo) <= 1609.344e * 5,1,0e))
      ,count_10 = count(*)
from dbo.point_of_interest
where LatLong.STDistance(@geo) <= 1609.344e * 10

เจตนาของเคียวรี json คือการเรียกใช้ฟังก์ชันนี้เป็นกลุ่ม ถ้าฉันเรียกว่าแบบนี้การแสดงแย่มากโดยใช้เวลาเกือบ 10 วินาทีเพียง 4 คะแนน:

select row=[key]
      ,count_1
      ,count_3
      ,count_5
      ,count_10
from openjson(@json)
cross apply dbo.fn_poi_in_dist(
            geography::Point(
                convert(float,json_value(value,'$[0]'))
               ,convert(float,json_value(value,'$[1]'))
               ,4326))

plan = https://www.brentozar.com/pastetheplan/?id=HJDCYd_o4

อย่างไรก็ตามการย้ายการสร้างภูมิศาสตร์ภายในตารางที่ได้รับนั้นทำให้ประสิทธิภาพในการทำงานดีขึ้นอย่างมากโดยทำแบบสอบถามให้เสร็จภายใน 1 วินาที

select row=[key]
      ,count_1
      ,count_3
      ,count_5
      ,count_10
from (
select [key]
      ,geo = geography::Point(
                convert(float,json_value(value,'$[0]'))
               ,convert(float,json_value(value,'$[1]'))
               ,4326)
from openjson(@json)
) a
cross apply dbo.fn_poi_in_dist(geo)

แผน = https://www.brentozar.com/pastetheplan/?id=HkSS5_OoE

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

การรันทั้งสองด้วยคำใบ้ที่เพิ่มเข้ามาในแบทช์จะมีน้ำหนักทั้งการสืบค้นเท่ากัน

รุ่นของเซิร์ฟเวอร์ Sql = Microsoft SQL Server 2016 (SP1-CU7-GDR) (KB4057119) - 13.0.4466.4 (X64)

ดังนั้นคำถามของฉันคือทำไมเรื่องนี้? ฉันจะทราบได้อย่างไรว่าฉันควรคำนวณค่าภายในตารางที่ได้รับหรือไม่


1
โดย "น้ำหนัก" คุณหมายถึงต้นทุนโดยประมาณ% จำนวนนั้นไร้ความหมายโดยเฉพาะอย่างยิ่งเมื่อคุณนำ UDFs, JSON, CLR ผ่านทางภูมิศาสตร์ ฯลฯ
Aaron Bertrand

ฉันรู้ แต่การดูสถิติ IO พวกเขาเหมือนกัน ทั้งสองทำ 358306 ตรรกะอ่านบนpoint_of_interestโต๊ะทั้งสแกนดัชนี 4602 ครั้งและทั้งสร้าง worktable และ workfile ตัวประมาณเชื่อว่าแผนเหล่านี้เหมือนกัน แต่ประสิทธิภาพนั้นบอกเป็นอย่างอื่น
Michael B

ดูเหมือนว่า CPU ที่แท้จริงเป็นปัญหาที่นี่อาจเป็นเพราะมาร์ตินชี้ให้เห็นไม่ใช่ I / O น่าเสียดายที่ค่าใช้จ่ายโดยประมาณนั้นมาจาก CPU และ I / O รวมกันและไม่ได้สะท้อนสิ่งที่เกิดขึ้นจริงเสมอไป หากคุณสร้างแผนจริงโดยใช้SentryOne Plan Explorer ( ฉันทำงานที่นั่น แต่เครื่องมือฟรีโดยไม่มีสตริง ) จากนั้นเปลี่ยนค่าใช้จ่ายจริงเป็น CPU เท่านั้นคุณอาจได้รับตัวบ่งชี้ที่ดีกว่าว่าจะใช้เวลา CPU ใด
Aaron Bertrand

1
@MartinSmith ยังไม่มีโอเปอเรเตอร์ต่อหมายเลข เราทำพื้นผิวเหล่านั้นในระดับคำสั่ง ขณะนี้เรายังคงใช้งานการเริ่มต้นจาก DMV ก่อนที่จะเพิ่มการวัดเพิ่มเติมเหล่านั้นในระดับที่ต่ำกว่า และเรากำลังยุ่งกับการทำงานอย่างอื่นที่คุณจะเห็นในไม่ช้า :-)
Aaron Bertrand

1
ป.ล. คุณอาจได้รับการปรับปรุงประสิทธิภาพให้ดียิ่งขึ้นโดยการทำกล่องทางคณิตศาสตร์อย่างง่ายก่อนทำการคำนวณระยะทางตรง นั่นคือตัวกรองครั้งแรกสำหรับผู้ที่มีค่าก่อนที่คุณจะทำที่ซับซ้อนมากขึ้น|LatLong.Lat - @geo.Lat| + |LatLong.Long - @geo.Long| < n และดียิ่งขึ้นคำนวณขอบเขตบนและล่างก่อนแล้วsqrt((LatLong.Lat - @geo.Lat)^2 + (LatLong.Long - @geo.Long)^2) LatLong.Lat > @geoLatLowerBound && LatLong.Lat < @geoLatUpperBound && LatLong.Long > @geoLongLowerBound && LatLong.Long < @geoLongUpperBound(นี่คือรหัสเทียมปรับให้เหมาะสม)
ErikE

คำตอบ:


15

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


ความแตกต่างคือในแผนอย่างรวดเร็วงานที่จำเป็นในการวิเคราะห์องค์ประกอบอาร์เรย์ JSON และสร้างภูมิศาสตร์จะทำ 4 ครั้ง (หนึ่งครั้งสำหรับแต่ละแถวที่ปล่อยออกมาจากopenjsonฟังก์ชั่น) - ในขณะที่มันทำมากกว่า 100,000 ครั้งในแผนช้า

ในการวางแผนที่รวดเร็ว ...

geography::Point(
                convert(float,json_value(value,'$[0]'))
               ,convert(float,json_value(value,'$[1]'))
               ,4326)

ถูกกำหนดให้Expr1000ในสเกลาร์คำนวณทางด้านซ้ายของopenjsonฟังก์ชัน สิ่งนี้สอดคล้องกับgeoคำนิยามตารางที่คุณได้รับ

ป้อนคำอธิบายรูปภาพที่นี่

Expr1000ในแผนได้อย่างรวดเร็วกรองและสตรีมการอ้างอิงรวม ในแผนช้าพวกเขาอ้างอิงการแสดงออกพื้นฐานเต็ม

สตรีมคุณสมบัติรวม

ป้อนคำอธิบายรูปภาพที่นี่

ตัวกรองถูกดำเนินการ 116,995 ครั้งโดยการดำเนินการแต่ละครั้งต้องมีการประเมินผลการแสดงออก มวลรวมมี 110,520 แถวที่ไหลเข้ามาเพื่อรวมและสร้างมวลรวมแยกสามรายการโดยใช้นิพจน์นี้ 110,520 * 3 + 116,995 = 448,555. แม้ว่าการประเมินแต่ละครั้งจะใช้เวลา 18 ไมโครวินาทีซึ่งจะเพิ่มเวลาเพิ่มขึ้น 8 วินาทีสำหรับการค้นหาโดยรวม

คุณสามารถเห็นผลของสิ่งนี้ในสถิติเวลาจริงใน XML แผน (บันทึกย่อเป็นสีแดงด้านล่างจากแผนช้าและสีน้ำเงินสำหรับแผนเร็ว - เวลาเป็นมิลลิวินาที)

ป้อนคำอธิบายรูปภาพที่นี่

มวลรวมของสตรีมนั้นมีเวลาที่ผ่านไปแล้ว 6.209 วินาทีมากกว่าลูกในทันที และตัวกรองจำนวนมากก็ถูกพาตัวไปด้วย สิ่งนี้สอดคล้องกับการประเมินผลนิพจน์พิเศษ


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


นอกจากนี้ถ้าฉันเปลี่ยนแบบสอบถามเพื่อใช้กากบาทเพื่อสร้างภูมิศาสตร์ฉันก็จะได้รับแผนการที่รวดเร็ว cross apply(select geo=geography::Point( convert(float,json_value(value,'$[0]')) ,convert(float,json_value(value,'$[1]')) ,4326))f
Michael B

โชคไม่ดี แต่ฉันสงสัยว่าจะมีวิธีที่ง่ายกว่าในการสร้างแผนที่รวดเร็วหรือไม่
Michael B

ขออภัยสำหรับคำถามมือสมัครเล่น แต่เครื่องมือใดที่แสดงในภาพของคุณ
BlueRaja - Danny Pflughoeft

1
@ BlueRaja-DannyPflughoeft เหล่านี้มีแผนการดำเนินการที่แสดงในสตูดิโอการจัดการ (ไอคอนที่ใช้ใน SSMS ได้รับการปรับปรุงในรุ่นที่ผ่านมาว่าเป็นเหตุผลสำหรับคำถาม)
มาร์ตินสมิ ธ
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.