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


12

我有两组来自卫星数据的地球测量数据,每组都有时间字段(均值朱利安日期为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) ) )

执行的计划是:

仅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) ) )

它消失了很长时间。显然,在8秒内,它可以找到100,000个时间匹配项,其中9个匹配项低于200 km,因此优化程序必须尝试一些次优的匹配项。该计划看起来与上面类似,但对距离进行了过滤(我猜是这样)。

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

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

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) ) )

具有两个索引的两个约束

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

我如何告诉查询优化器先使用MJD索引查找,然后再使用空间索引(或者这是它已经在做什么),有什么办法可以告诉它预期有多少个匹配项来帮助它?如果它能在8秒内计算出100,000个匹配项,且距离在200公里之内有9个,那么增加空间索引是否就可以使速度更快而不是变慢?

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

编辑:要回答没有提示的计划是什么样的问题,这(并且要花很多时间):

没有提示

也许还值得一提的是,一个表中几乎有100万条记录,而另一张表中有800万条记录


如果删除这些提示,您的查询计划是什么样的?
赞恩(Zane)

@Zane,我编辑了帖子并添加了无提示查询计划。它用扫描代替了寻道,而且时间太糟糕了。
user261963

Answers:


6

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

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

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

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

如果在这样的两个范围内过滤数据,将很难使用索引来应用第二个过滤器。如果时间过滤器比较紧凑,最好告诉它不要使用空间索引。

如果两者都很大,并且只有两者紧密,那么您会遇到一个更复杂的问题,人们已经尝试解决了很长时间,并且可以通过覆盖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) ) );

请注意,我故意将可比性除以1000,然后再将其除以200。我希望这项工作可以在Key Lookup中完成。

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


我不知道它是否会改变任何东西,但是时间过滤器更具选择性。
user261963

好。那么可以找到所有时间匹配的行,然后检查每个没有索引的位置是否可以接受?
罗伯·法利

...因此该计划看起来像您的原始计划,但是有一个额外的谓词或过滤器。
罗伯·法利

建议您进行一些修改,并快速进行修改。您不需要暗示m,只需暗示h。尽管如果可以交换要添加1/8的那个,但要确保您正在修改较小表中的列,并使用这些值查找较大的表,这也将有所帮助。如果h为8M且m为1M,则保留BETWEEN谓词,并仅提示h。如果相反,则更改谓词和提示(但比更改提示更好的是将这些列添加到索引中)。
罗布·法利

最后,只要我在m之间而不是在h之间做h,那么取出所有表提示似乎效果最好。该查询完全不再使用GeoPoint索引,但是无论如何都没有有效地使用它们。我将GeoPoint列包含在MJD索引中,这很有帮助。select top 10000 h.Time, m.Time, m.GeoPoint.STDistance(h.GeoPoint), h.mjd-m.mjd from L2V5.dbo.header h join L2.dbo.MLS_Header m on m.GeoPoint.STDistance(h.GeoPoint)<200000 and m.mjd between h.mjd-.125 and h.mjd+.125 order by h.mjd
user261963
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.