请教各位老哥, PostgreSQL、PostGIS 基于地理空间的查询如何优化速度?

2022-05-14 11:52:16 +08:00
 liuguangxuan

场景:

可以理解为:记录飞机飞行的轨迹,把经、纬度点,高度、速度、航向存入PostgreSQL数据库,并在经纬度列建立 gist 索引。

数据量大概在 1 亿条左右。

想实现查询指定区域范围(圆形、矩形、多边形)内的轨迹。

测试:

随机在经度(-180°,180°),纬度(-90°,90°)的范围内生成 1 亿个坐标点,保留小数点后 5 位小数,并存入数据库,测试在指定的范围内的查询速度。

查询矩形区域32°*32°的范围,查询出来的记录数约为 150 万条,用时 15 分钟左右。

问题:

  1. 想请问各位老哥,如何把查询的时间给优化下去,现在耗时 15 分钟有点儿太长了。
  2. 如果不关注实时的点,只关注整体的轨迹线,如何把轨迹线抽取出来?做压缩?这样查询速度会不会快一些。
  3. 如果抽取轨迹线的话,如何保留速度、航向、高度等特征值。想以后做分析用,比如突然转向、突然减速、突然高度骤降等。
3048 次点击
所在节点    PostgreSQL
36 条回复
nuistzhou
2022-05-14 12:14:57 +08:00
你的 Gist 是不是有问题呀?一亿条数据也不应该这么久啊。另外,单看返回条数呢?是不是大部分时间花在返回数据本身上了?
beginor
2022-05-14 12:34:16 +08:00
经纬度保存成空间数据类型 Geometry 然后再加索引试试,这样可以用上空间索引
liuguangxuan
2022-05-14 12:47:03 +08:00
@nuistzhou #1
@beginor #2
老哥,经纬度索引列,应该是没问题,类型为 geometry(Point),我用\d tablename ,能查到索引。只是建立索引的时候没有添加编码 4326 ,请问这个影响大吗?

另外可能和我测试环境的配置有关系,我用的是腾讯云 2 核 8G 内存,PostgreSQL 的配置文件保持默认的设置。

提高服务器硬件资源配置是一方面,老哥可否指点一下其它提高查询性能的方法。
liuguangxuan
2022-05-14 12:48:45 +08:00
@nuistzhou #1 如果单看返回条数的话,使用 select count(*),时间也差不太多。
iseki
2022-05-14 13:12:05 +08:00
explain (analyze on, timing on)看看慢在哪呗
beginor
2022-05-14 13:12:54 +08:00
@liuguangxuan 坐标字段声明坐标系,空间数据类型建议使用 SP-GiST 索引类型, 查询时的空间参数也使用相同的坐标系, 空间函数 st_contains 可以改为 st_intersect 或者 && 算符
a90120411
2022-05-14 13:29:23 +08:00
别查 Point ,查 Line 。
用点来生成线,在线对象数据中同时保存与点集合的业务数据关联。
wd
2022-05-14 14:20:09 +08:00
st_contains 走索引吗?好像不走?
v2eb
2022-05-14 14:45:34 +08:00
分析突然减速的这种场景,好像和坐标没有必然的联系吧,还是没有速度这个数据条目?
nuistzhou
2022-05-14 15:49:26 +08:00
1. explain 看看吧,前面的老哥提到了,看看是不是 hit 太多了
2. 试试 st_geohash 吧,可以把点聚集起来,然后建个空间索引,hit 应该会降低不少
3. 试试 @ 这个 operator
liuguangxuan
2022-05-16 22:02:09 +08:00
@beginor #6 老哥,我大概按你的方法测试了一下,分别测试了 st_contains 、st_intersects 、&&在不同索引( gist,sp-gist )下的查询情况,并且换了一台服务器。每次测试均重启了服务器。

总体而言,gist 索引性能好于 sp-gist 索引,首次查询 st_intersects 性能比较好,第二次查询&&性能比较好。

测试结果和老哥说的有点儿出入,能不能帮忙解答一下原因,还是我测试的方式不太对?

beginor
2022-05-17 09:37:44 +08:00
SP-GiST 是带分区的 GiST ,至于谁比谁更好,要看具体场景和数据类型,实际上也差不了多少。
dzdh
2022-05-17 15:33:16 +08:00
完整 sql 方便贴一下吗

explain(timing, analyze, buffers) 或者是 explain 结果
liuguangxuan
2022-05-17 15:39:17 +08:00
换了一台性能比较好的服务器,再加上二次查询的原因,可能内存中有缓存,所以现在比较快,大约 64°*64°的区域,在 6~7 秒左右,老哥还有没有优化的方法?

liuguangxuan
2022-05-27 09:42:36 +08:00
@a90120411 #7 老哥,我现在用点生成线了。

但是我如何查询在指定区域(Polygon)内的线(geometry(LineString))呢?即部分包含的线。

我使用 ST_contains 、st_intersects 函数都查不出来。
a90120411
2022-05-27 10:41:54 +08:00
@liuguangxuan 用 ST_Covers
liuguangxuan
2022-05-27 10:48:24 +08:00
@a90120411 #16
多谢老哥回复。

再请教一下老哥,如图所示,一个 Polygon 和一个 LineString:
1 、我想求相交区域(绿色部分)的线,应该用哪个函数啊?
2 、我想求非相交区域(红色部分)的线,应该用哪个函数啊?
a90120411
2022-05-27 10:49:12 +08:00
@a90120411 说错了,应该用 ST_Intersects
a90120411
2022-05-27 11:04:12 +08:00
@liuguangxuan 判断包含关系,用 ST_Intersects 。

1 、交集 ST_Intersection

2 、差集 ST_Difference
liuguangxuan
2022-05-27 11:14:46 +08:00
@a90120411 #19

1 、交集没问题,一切正常。

2 、但是差集的话,会把旁边的那条无关的线也返回。我想实现只返回有交集的线的差集。😂

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/852771

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX