2

我在 SQL Server 2008 R2 Express 数据库中有大约 7500 万条记录。每个都是对应于某个值的 lat long。该表有地理列。我正在尝试为给定的纬度经度(点)找到一个最近的邻居。我已经有了一个带有空间索引的查询。但是根据记录在数据库中的位置,比如第一季度或上季度,查询可能需要大约 3 到 30 秒才能找到最近的邻居。我觉得这可以通过优化查询或空间索引来优化以提供更快的结果。现在应用了一些具有默认设置的空间索引。这是我的表和查询的样子。

CREATE TABLE lidar(
    [id] [bigint] IDENTITY(1,1) NOT NULL,
    [POINTID] [int] NOT NULL,
    [GRID_CODE] [numeric](17, 8) NULL,
    [geom] [geography] NULL,
 CONSTRAINT [PK_lidar_1] PRIMARY KEY CLUSTERED ([id] ASC)
 WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF, 
 ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
) ON [PRIMARY]

我正在使用的空间索引:

CREATE SPATIAL INDEX [SPATIAL_lidar] ON [dbo].[lidar] ([geom]) USING  GEOGRAPHY_GRID 
WITH (
GRIDS =(LEVEL_1 = MEDIUM,LEVEL_2 = MEDIUM,LEVEL_3 = MEDIUM,LEVEL_4 = MEDIUM), 
CELLS_PER_OBJECT = 16, PAD_INDEX  = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF,  
ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]

这是我正在使用的查询:

declare @ms_at geography = 'POINT (-95.66 30.04)';
select TOP(1) nearPoints.geom.STAsText()as latlon 
from
(
select r.geom
from lidar r With(Index(SPATIAL_lidar))
where r.geom.STIntersects(@ms_at.STBuffer(1000)) = 1
) nearPoints

这是我的数据库中的 lat longs 示例。给出准确度和密度的概念。所有 7000 万条记录都针对一个城市(激光雷达数据)

POINT (-95.669434934023087 30.049513838913736)

现在这个查询给了我上面描述的结果,但我想尽可能地提高性能。我的猜测是通过调整空间索引的默认值,我可能能够提高性能。这有什么线索吗?

我尝试将缓冲区从 10 更改为 1000,但结果几乎相同。

也欢迎任何其他改进性能的建议。

这是我现在使用的系统:

Windows 7 64bit Professional
Intel(R) Core(TM)2 Quad CPU    Q9650  @ 3.00GHz (4 CPUs), ~3.0GHz
Ram: 8 GB
NVIDIA GeForce 9500 GT
4

4 回答 4

2

抱歉,但这不是 SQL 答案,而是假设您的数据受到某些限制的情况下获得可预测性能的一种方式。

数据多久变化一次?如果可能,您能否预先计算每个实体 5 个最近邻居的图表,并使用它来加快您的选择速度。?

如果这些数据大多是只读的,那么...

这些点的分布有多均匀?如果分布相当均匀且众所周知,那么您是否可以通过将每个坐标和索引存储在哈希表中来滚动您自己的空间映射。

如果您不需要数据库中的数据,请将其移出内存映射文件以进行快速哈希查找。(70m 记录应该很容易放入内存中)。

我已经使用这种架构为展示广告和搜索引擎相关性生成亚毫秒级的查找。

==阐述==

您只需创建一个固定大小正方形的网格(如棋盘),然后将每个点映射到网格中,然后创建属于每个网格框的对象列表 - 如果您调整每个网格的大小正确的盒子,你应该在每个方块中平均有 5-50 个点——这原则上是一个四叉树,但为了简单起见没有树。

对于将所有数据分散到桶中后为空的每个桶,您添加有关哪些最近的桶包含数据的信息。

您现在可以从左到右对每个存储桶进行编号,以便每个存储桶都有一个唯一的编号,该编号可以从坐标中计算出来——然后您将每个存储桶插入一个哈希表,或者如果空间允许,就像一个直查表。

现在,当您进行查询时,您只需计算将映射到哪个存储桶,您将获得该存储桶中的对象列表,或者您将获得一个“空”存储桶,其中包含指向具有内容的最近存储桶的指针.

这将为您提供您正在寻找的对象的第一个候选列表,现在您只需运行并查看最接近的对象。

在 99% 的情况下是这样 - 但如果您担心 (a) 在下一个存储桶中有一些实际上更接近的候选对象,那么只需检查周围的 8 个存储桶,看看是否可以找到更近的地方。

如果您现在还想获取所有最近对象的列表,那么还要为每个对象计算一个由 5 个最近邻居组成的简单网络,因此您最终会得到一个像 A->{B,C,D 这样的数据结构,E,F}, B->{A,D,G,H,I}, C->{A,J,K,G,M}....

这将形成一个简单的网络,您现在可以在此处使用Dijkstra的变体进行遍历,以获取与您最近点相邻的所有点。

构建数据结构需要时间,但一旦完成,正确查找和返回数据集可以在亚毫秒内完成(不包括任何 http 或机外通信)

希望这可以帮助。

于 2011-07-11T20:43:06.010 回答
0

阅读这篇关于空间索引的文章。

我的猜测是你的初级过滤器效率很低。您可能需要第一级的网格密度很高,因为您的点非常密集。我一直在努力解决的一个问题是如何使 LEVEL1 的密度大于 256(HIGH)。我很惊讶微软强迫我们只有 3 个网格密度选项。

于 2011-08-23T16:58:53.747 回答
0

对于 SQL Server 2008 上的常规最近邻查询,请尝试 Isaac 在其博客中记录的方法,该方法使用数字表来增加查找范围,直到找到足够的候选者。另一个建议是尝试改变网格密度 - HHHH 或 HHMM 可能更适合密集点。

在 Sql Server Denali 中,优化最近邻查询的这一功能也将使用常规的 SELECT TOP ... ORDER BY 语法本机支持。

作为旁注,在您的示例中,您的查询中似乎缺少 ORDER BY 距离子句以与顶部一起使用?您当前的查询将返回距离目标 1000 米以内的点,但不一定是最近的点。

于 2011-07-12T14:14:23.380 回答
0

您是否尝试过使用索引设置?我通常对每个单元格使用更高的对象,对所有网格级别使用“高”。见下文:

CREATE SPATIAL INDEX [SPATIAL_lidar] ON [dbo].[lidar] ([geom]) USING  GEOGRAPHY_GRID  WITH ( GRIDS =(LEVEL_1 =   HIGH,LEVEL_2 = HIGH,LEVEL_3 = HIGH,LEVEL_4 = HIGH),  CELLS_PER_OBJECT = 64, PAD_INDEX  = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF,   ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY] 
于 2011-07-13T08:23:57.233 回答