我正在运行一个包含大型业务地址表的数据库服务器。一个应用程序连接到它,接收用户坐标和他们正在寻找的业务类型,并返回离该用户最近的业务。
最初,我的应用程序使用一个简单的SELECT语句来查找最近的业务,返回所有业务名称的表格,并在应用程序端进行一些排序(这是用户的坐标数据和地址的使用位置)找到最近的一个:
Select * from my_table where business_type = 'bakeries';
这对我来说似乎并不理想,因为在应用程序端有一个明显的滞后半秒,因为它通过数据排序找到最近的。我目前正在调查是否可以在数据库结束时更快地完成所有计算。因此,我发现了POSTGIS及其功能,以找到最接近输入的坐标。使用它的功能,我想出了为每个用户请求执行的查询:
SELECT *, ST_Distance(ST_GeogFromText('SRID=4326;POINT(user_long user_lat)'), geom, false) as
distance from my_table where business_type = 'Insurance' order by distance limit 1;
这似乎是更快的响应,特别是对于表中有很多列表的业务类型(例如保险公司)。但是,当我尝试对来自的请求进行压力测试时,我注意到它的扩展性非常大。对URL的500个并发请求很快导致数据库CPU使用率达到100%,因此这种方法在高峰时间会失败。
"Limit (cost=12804.92 rows=1 width=261)"
" -> Sort (cost=12804.91..12878.92 rows=29602 width=261)"
" Sort Key: (_st_distance('0101000020E61000007AC7293A927F52C0D34D621058614440'::geography, (geom)::geography, '0'::double precision, false))"
" -> Index Scan using business_name_index on my_table (cost=0.43..12656.90 rows=29602 width=261)"
" Index Cond: (business_type = 'Insurance'::text)"
有没有办法使这个更可行或者我应该放弃这个想法并尝试另一条路线?我知道一种替代方法是使用ST_DWithin
查找特定半径内的所有最近地址(如here所示),但我无法定义最小距离,因为默认情况下某些距离可能太远。
我第二个Yevgens回答,假设您的企业的坐标也是POINT
而不是POLYGON
或其他东西,这可能导致与<->
使用边界框之间的近距离内的距离不一致。但ST_Distance()
does不使用索引,所以如果性能是最重要的,那么这就是要走的路。
您可以在这里阅读有关您的具体问题的更多信息:http://postgis.net/workshops/postgis-intro/knn.html
你的geom
-column上需要一个2d GiST索引才能使用btw的<->
函数。
CREATE INDEX idx_mytable_geom ON my_table USING Gist(geom);
你也可以考虑使用ST_GeomFromText()
并将你的geom
-column转换为geometries
,因为geometries
似乎比geographies
表现更好。
在这里找到更多:https://medium.com/coord/postgis-performance-showdown-geometry-vs-geography-ec99967da4f0
或者甚至更好地使用ST_MakePoint()
,它也创造geometries
并且比ST_GeomFromtext()
更快。
点击这里:https://gis.stackexchange.com/questions/58605/which-function-for-creating-a-point-in-postgis
虽然这只是一个小的改进,因为你只为每个查询创建一个点,但它可能会加起来。
所以你的代码看起来像:
SELECT a.*, ST_SetSRID(ST_MakePoint(lng lat), 4326) <-> a.geom as dist
FROM my_table a
where business_type = 'Insurance'
ORDER BY dist;
这些是我的想法。
我想,你仍然有一个改进你的应用程序性能的空间,使用<->
运算符(而不是ST_Distance()
),因为它利用空间索引并允许更快地进行空间查找。