我有一些表,其中包含存储为 lat long 对的属性的事务。(在我的示例架构中,列和数据点更多)。
一个常见的请求是查找在特定点 X 英里范围内发生的交易,并且只检索附近每个物业发生的 5 次最近的交易。
为了完成这项工作,我决定添加一个封装最新逻辑的视图:
create or alter view dbo.v_example
with schemabinding as
select example_id
,transaction_dt
,latitude
,longitude
,latlong
,most_recent= iif(row_number() over (partition by latitude,longitude order by transaction_dt desc) < 5,1,null)
from dbo.example;
因此查询可能如下所示:
select *
from dbo.v_example
where latlong.STDistance(geography::Point(40,-74,4326)) <=1609.344e1
and most_recent = 1
不幸的是,当我通过视图查询时,SQL Server 不想使用空间索引。如果我删除schemabinding
并尝试在视图上添加提示,我会发现查询处理器无法创建计划。
如何封装逻辑并仍然让它使用我的空间索引?
该表要大得多,扫描它然后进行聚集索引查找然后找到附近的点要慢得多。
窗口功能和视图
最近我回答了一个关于视图和窗口功能的不同问题,但并非所有答案都适用于此处。
两个区别是这个例子
geography
在窗口函数上使用了数据类型和过滤器。这里的积极部分是你没有绑定到窗口函数,并且可以使用类似的东西CROSS APPLY
来获得一个latitude
&longitude
组合的最接近的结果。上一个问题+答案
简而言之,在应用过滤之前计算窗口函数。
例如
可以在Paul White 2013 年的这篇博文中找到有关窗口功能和视图的更多信息。
测试
作为第一个测试,当
ROW_NUMBER()
从视图中省略时结果很清楚产生预期的高性能查询计划。
DB<>小提琴
但是你显然仍然想要额外的过滤
保持视图+窗口功能
您可以选择在之后添加窗口功能,如下所示:
&
再次导致预期的执行计划。
DB<>小提琴
使用内联表值函数 + 窗口函数
产生您期望的查询计划。
DB<>小提琴
使用 CTE + 窗口函数
使用
CROSS APPLY
和TOP(4)
不使用窗口函数我使用了,因为结果集不是
top(4)
基于< 5
<= 5
使用该
CROSS APPLY
方法时,还要添加一个索引,以删除索引假脱机和排序:不用说,您可以将
CROSS APPLY
解决方案添加到视图中,并以与以前相同的方式查询它,这里有一个示例。以上所有示例都在一个 DB<>Fiddle here中。MichaelB结束解决方案评论
DB<>小提琴
&