2016-12-23 35 views
5

我有一个性能查询最近的商店:SQL服务器:地理搜索性能 - 查询最近的商店

我们有一个包含一个全国各地的50,000条记录(商店/销售位置点)的表。

每条记录​​都使用此语法

CREATE SPATIAL INDEX [LOCATION_geoIndex] 
ON [dbo].[StoreLocations] ([LOCATION_geo]) 
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] 
GO 

我有一个存储过程返回

[LOCATION_geo] [geography] 

性能也是我创建空间索引在该位置列类型“地理”的location列用户当前位置最近的1000家商店。

USE [CompanyDB] 
GO 
SET STATISTICS TIME ON; 
GO 
declare @point geography; 
    set @point = geography::Point(49.2471855, -123.1078987, 4326); 

    SELECT top (1000) [id] 
      ,[Location_Name] 
      ,[LOCATION_geo]from [MYDB].[dbo].[StoreLocations] 
     where [LOCATION_geo].STDistance(@point) <= 10000 
     ORDER BY [LOCATION_geo].STDistance(@point) 

问题是查询总是需要656毫秒到800毫秒。这对我们的网站来说是不可接受的,因为我们期望太多的同步调用。

(1000行(S)的影响)

SQL Server的执行时间:CPU时间= 923毫秒,经过的时间= 1511毫秒。

注:大部分商店位于一些城市(约10个城市)。

另外我注意到聚集索引查找成本大于总查询成本的45%。

所以我的问题是有没有更好的方法来提高该查询的性能?

+0

是否使用了空间索引?你能否确认它是通过执行计划使用的? – gotqn

+0

是的,它使用,成本8%,估计行大小17 B,订购:真,预计执行次数109.8。 –

+0

此外,该指数在执行计划中总是给出警告“列没有统计数据:.... SRID,....pk0“,实际上我不知道它是什么意思 –

回答

1

我会建议添加一个名为distance的列,距离距离Point(0,0,0)的LOCATION_geo的距离。请参见下面的示例插入语句:

INSERT INTO [GWDB].[dbo].[StoreLocations] 
      ([id] 
      ,[Location_Name] 
      ,[LOCATION_geo] 
      ,[Distance]) 
    Values(@id 
      ,@Location_Name 
      ,@LOCATION_geo 
      ,@LOCATION_geo..STDistance(Point(0, 0, 0)) 

你也应该对新列的距离创建索引,并如下改变你的存储过程:

USE [CompanyDB] 
GO 
SET STATISTICS TIME ON; 
GO 
declare @point geography; 
declare @distance float; 
    set @point = geography::Point(49.2471855, -123.1078987, 4326); 
    set @distance = @point.STDistance(geography::Point(0, 0, 0); 

    SELECT top (1000) [id] 
      ,[Location_Name] 
      ,[LOCATION_geo]from [GWDB].[dbo].[StoreLocations] 
     where 
     distance < @distance AND 
     [LOCATION_geo].STDistance(@point) <= 10000 
     ORDER BY [LOCATION_geo].STDistance(@point) 
+0

它值得一试。但是这不会产生准确的结果,我想如果在西方的搜索点,这个查询将只得到东部商店(搜索点东部的商店)。 –

+0

我试过了,它并没有科学地提高性能,因为我认为低性能的主要原因是声明的顺序。 谢谢。 –

0

我不知道有多好,这将在你的工作应用程序,在某些情况下,这会更快,但在其他情况下会更慢。当您搜索的点靠近您的数据时,此搜索过程更快。当搜索点距离数据越远时,速度越慢。

在我的场景中,我所有的点都比较接近(1600万条记录)。这些是我看到的速度差异。

|--Search Location--|--STIntersects() time--|--Numbers time--| 
-------------------------------------------------------------- 
|Close    |5 seconds    |700 ms   | 
|Far    |90 ms     |4 seconds  | 

基本上,这个想法是逐步扩大使用数字表您的搜索区域。

DECLARE @point GEOGRAPHY = GEOGRAPHY::Point(49.2471855, -123.1078987, 4326) 
DECLARE @MaximumRaidus INT = 10000 

SELECT TOP 100 
    ID, 
    Location_Name, 
    Location_geo 
FROM 
    GWDB.dbo.StoreLocations WITH(INDEX([LOCATION_geoIndex])) 
CROSS JOIN 
    GWDB.dbo.Numbers N 
WHERE 
    N.n BETWEEN 0 AND SQRT(@MaximumRadius) 
    AND Location_geo.STIntersects(@Point.STBuffer(POWER(N.n,2))) = 1 
ORDER BY 
    N.n 
+0

谢谢,但我没有得到dbo.Numbers表是什么?我没有这样的桌子。 –

+0

@ Tarek_El-Mallah一个数字表只是一个整数表。即表号有一列(n INT),其值为0到10000左右。它们对于做这样的事情非常有用,或者填补数据中的空白,或者为直方图分割数据等。谷歌这个术语,你应该找到一些关于它们的用法以及如何创建它们的参考。 – hcaelxxam