ฉันมีแบบสอบถามซึ่งใช้สตริง 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)
ดังนั้นคำถามของฉันคือทำไมเรื่องนี้? ฉันจะทราบได้อย่างไรว่าฉันควรคำนวณค่าภายในตารางที่ได้รับหรือไม่
point_of_interest
โต๊ะทั้งสแกนดัชนี 4602 ครั้งและทั้งสร้าง worktable และ workfile ตัวประมาณเชื่อว่าแผนเหล่านี้เหมือนกัน แต่ประสิทธิภาพนั้นบอกเป็นอย่างอื่น
|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
(นี่คือรหัสเทียมปรับให้เหมาะสม)