如何优化查询,使其先搜索一个索引,然后再搜索另一个索引

use*_*963 12 performance index join sql-server spatial query-performance

我有两组来自卫星数据的地球测量值,每组都有时间场(平均朱利安日期的 mjd)和地理位置(GeoPoint,空间),我正在寻找两组之间的巧合,以便它们的时间匹配阈值3 小时(或 0.125 天),它们之间的距离在 200 公里以内。

我已经为表和空间表上的 mjd 字段创建了索引。

当我刚刚加入时间限制时,数据库会在 8 秒内计算 100,000 个匹配项,并计算该时间内所有 100,000 个匹配项的距离。查询如下所示:

select top 100000 h.Time, m.Time, h.GeoPoint.STDistance(m.GeoPoint)/1000.0
from L2V5.dbo.header h join L2.dbo.MLS_Header m
on h.mjd between m.mjd-.125 and m.mjd+.125
option( table hint ( h, index(ix_MJD) ), table hint( m, index(ix_MJD) ) )
Run Code Online (Sandbox Code Playgroud)

并且执行的计划是:

只有 mjd 约束

排序后,有 9 个距离在 200 公里以下,因此存在匹配项。问题是,当我添加距离约束并运行它时,

select top 10 h.Time, m.Time, h.GeoPoint.STDistance(m.GeoPoint)/1000.0
from L2V5.dbo.header h join L2.dbo.MLS_Header m
on h.mjd between m.mjd-.125 and m.mjd+.125
and h.GeoPoint.STDistance(m.GeoPoint)<200000
option( table hint ( h, index(ix_MJD) ), table hint( m, index(ix_MJD) ) )
Run Code Online (Sandbox Code Playgroud)

它会消失很长时间。显然,在 8 秒内,它可以找到 100,000 个时间匹配项,其中 9 个在 200 公里以下,因此优化器必须尝试次优的方法。该计划看起来类似于上面的距离过滤器(我猜)。

有空间常数,无空间过滤器

我可以强制使用空间索引:

select top 5 h.Time, m.Time, h.GeoPoint.STDistance(m.GeoPoint)/1000.0 
from L2V5.dbo.header h join L2.dbo.MLS_Header m 
on h.GeoPoint.STDistance(m.GeoPoint)<200000
and h.mjd between m.mjd-.125 and m.mjd+.125 
option( table hint ( h, index(ix_MJD), index(ix_GeoPoint) ), table hint( m, index(ix_MJD) ) )
Run Code Online (Sandbox Code Playgroud)

两个索引的两个约束

然后需要 3 分钟才能找到 5 个匹配项。

我如何告诉查询优化器首先使用 MJD 索引查找,然后使用空间索引(或者它已经在做什么),有什么方法可以通过告诉它期望多少匹配来帮助它?如果它可以在 8 秒内计算 100,000 个匹配,其中 9 个低于 200 公里,那么添加空间索引不应该使它更快而不是更慢吗?

感谢您提供任何其他提示或想法。

编辑:要回答没有提示的计划是什么样子的问题,这(并且需要永远):

没有提示

可能还值得一提的是,一张表几乎有 1M 条记录,另一张表有 8M 条记录

Rob*_*ley 6

问题在于它可能(并且知道空间索引,可能会)假设空间过滤器将比时间过滤器更具选择性。

但如果你在 200 公里内有几百万条记录,那么情况可能会更糟。

您要求它查找 200 公里内的记录,这会返回按某种空间顺序排序的数据。在那里找到时间接近的记录意味着检查每个记录。

否则,您正在按时间查找记录,并按时间顺序获得结果。然后,将此列表过滤到 200 公里半径是检查每个列表的问题。

如果像这样过滤两个范围内的数据,则很难使用索引应用第二个过滤器。如果时间过滤器更严格,您最好告诉它不要使用空间索引。

如果两者都很大,而且只有放在一起才会紧密,那么您会遇到一个更复杂的问题,人们已经尝试解决了很长时间,并且可以通过涵盖 3D(及更高版本)的索引很好地解决该问题空间。除了 SQL Server 没有它们。

对不起。

编辑:更多信息...

这与查找涵盖特定时间点的时间范围类似。当您搜索在该点之前开始的记录时,您会遇到一团无序的结束时间 - 反之亦然。如果您在电话簿中查找姓氏以 F 开头的人,您不可能希望很容易找到名字以 R 开头的人。出于同样的原因,名字的索引也无济于事。当您的第一个索引不相等时,很难在下一个索引中查找内容。

现在,如果您可以将日期过滤器更改为等式过滤器(或一系列等式过滤器),那么您就有机会,除了空间索引是一种特殊类型的索引并且不能用作第二级一个综合指数。

恐怕你的处境很尴尬。:(

编辑:尝试:

select top 100000 h.Time, m.Time, h.GeoPoint.STDistance(m.GeoPoint)/1000.0
from L2V5.dbo.header h join L2.dbo.MLS_Header m
on h.mjd between m.mjd-.125 and m.mjd+.125
where h.GeoPoint.STDistance(m.GeoPoint)/1000.0 < 200
option( table hint ( h, index(ix_MJD) ) );
Run Code Online (Sandbox Code Playgroud)

请注意,在与 200 进行比较之前,我特意通过除以 1000 来打破 sargability。我希望这项工作在 Key Lookup 中完成。

请注意,您可以通过在两个 ix_MJD 索引中包含 GeoPoint 和 Time 来避免查找(和提示)的需要。这肯定会从查询计划中消除一些热量。