我正在运行一个包含大型企业地址表的数据库服务器。已连接一个应用程序,该应用程序接收用户坐标和他们要查找的业务类型,并返回离该用户最近的业务。
最初,我的应用使用简单的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所示),但我无法定义最小距离,因为默认情况下某些距离可能太远。
答案 0 :(得分:2)
我第二个叶夫根回答,假设您的业务坐标也是POINT
而不是POLYGON
之类的东西,这可能导致距离{{1 }}使用边界框。但是<->
不使用索引,因此,如果性能是重中之重,那么这就是要走的路。
您可以在此处阅读有关特定问题的更多信息: http://postgis.net/workshops/postgis-intro/knn.html
您需要在ST_Distance()
列上使用2d GiST索引,以使geom
函数使用btw。
<->
您还可以考虑使用CREATE INDEX idx_mytable_geom ON my_table USING Gist(geom);
并将ST_GeomFromText()
列转换为geom
,因为geometries
的表现似乎比geometries
更好。
在此处找到更多信息: https://medium.com/coord/postgis-performance-showdown-geometry-vs-geography-ec99967da4f0
甚至更好地使用geographies
,它也可以创建ST_MakePoint()
,并且比geometries
快。
在这里检查: https://gis.stackexchange.com/questions/58605/which-function-for-creating-a-point-in-postgis
尽管这将是一个较小的改进,因为您每次查询只能创建一个点,但它可能加起来。
所以您的代码如下:
ST_GeomFromtext()
这些是我的想法。
答案 1 :(得分:1)
我想,您仍然可以使用<->
运算符(而不是ST_Distance()
)来提高应用程序的性能,因为它利用了空间索引并且可以更快地进行空间查找。