Postgres查询运行速度很慢

时间:2017-08-15 13:23:47

标签: sql postgresql gis postgis postgresql-9.4

SELECT st.id
FROM
       station st, strike s
WHERE s.srikedatetime > (current_timestamp - interval '20 seconds')  and srikedatetime < current_timestamp
    AND ST_Distance_Sphere(st.Geometry, s.strikepoint)/1000 <= st.radius

这个想法是当一次打击命中时,它可能是基于站点监视半径的多个站点的边界。我需要选择在过去20秒内受到任何罢工影响的所有电台。在20秒内我可以进行数千次攻击,并且每20秒执行一次查询时,CPU会变高,查询需要几分钟才能完成。当CPU不高时,它以毫秒运行。

查询计划:

"Nested Loop  (cost=0.42..505110.20 rows=21 width=7)"
"  Join Filter: ((_st_distance(geography(a.Geometry), geography(s.strikepoint), 0::double precision, false) / 1000::double precision) <= (a.radius)::double precision)"
"  ->  Index Only Scan using dup_strike_constraint on strike s  (cost=0.42..8.45 rows=1 width=36)"
"        Index Cond: ((srikedatetime > (now() - '00:00:20'::interval)) AND (srikedatetime < now()))"
"  ->  Seq Scan on station  st  (cost=0.00..505084.86 rows=62 width=549)"

我尝试了内连接,类似这样的

Inner JOIN strike s ON ST_Distance(a.Geometry, s.strikepoint) < 1

并尝试了ST_DWithin in where子句和分组仍然很慢。

ST_DWithin(s.strikepoint,a.Geometry, a.radius)

请问有什么想法吗?我有罢工和车站表的索引。

st.strikepoint和a.geomerty列的数据类型是几何。  坐标系是4326。 谢谢!

3 个答案:

答案 0 :(得分:1)

您可以创建Lazy Materialized View来仅存储您需要的数据。如果你只查询一个表而不是加入'station'和'strike'表,它会快得多。

显然,您的懒惰表应该正确编入索引,特别是如果您不打算定期“清理”数据。

其他选项可能是使用TEMP表来处理数据,如果不需要历史存储它并且您在一个会话中处理数据。 TEMP表只对一个会话可见,并在会话结束时'死'。您可以随时创建它们并销毁它们,但在这种情况下,您应该注意内存使用情况。

希望它有所帮助。

答案 1 :(得分:0)

一旦您的工作站得到改变,您就可以创建几何类型的字段,反映多边形,代表工作站的注册区域。即使用默认值ST_Buffer(Geometry, radius/1000)。并使用ST_Contains(st.the_polygon, s.strikepoint)检查点击。

如果没有加速,你可以在Station多边形上引入额外的索引。

答案 2 :(得分:0)

我会尝试通过减少可能的匹配来减少可能代价昂贵的函数ST_Distance_Sphere的使用。您不必为每个可能的匹配使用精确的球形距离,而是首先检查工作站周围的多维数据集,并且仅通过ST_Distance_Sphere()检查多维数据集内的匹配。

SELECT st.id
FROM
       station st, strike s
WHERE s.srikedatetime > (current_timestamp - interval '20 seconds')  and srikedatetime < current_timestamp
    AND ST_Distance_Sphere(st.Geometry, s.strikepoint)/1000 <= st.radius
    and s.strikepoint.x between st.Geometry.x - st.radius*1000 and st.Geometry.x + st.radius*1000
    and s.strikepoint.y between st.Geometry.y - st.radius*1000 and st.Geometry.y + st.radius*1000
    and s.strikepoint.z between st.Geometry.z - st.radius*1000 and st.Geometry.z + st.radius*1000

在下一步中,您可以将st.Geometry.x - st.radius * 1000存储为st.range_x_negative,以防止在连接期间进行计算。