【问题标题】:Postgres query running very slowPostgres 查询运行很慢
【发布时间】:2018-01-23 10:17:20
【问题描述】:
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

并且还在 where 子句和分组中尝试了 ST_DWithin 仍然很慢。

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

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

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

【问题讨论】:

  • 请使用这些列的数据类型以及使用的坐标系更新问题。
  • 更新了问题,st.strikepoint 和 a.geomerty 列的数据类型是几何。坐标系为 4326。

标签: sql postgresql gis postgis postgresql-9.4


【解决方案1】:

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

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

如果不需要历史存储数据并且您在一个会话中处理数据,则可以使用 TEMP 表来处理数据。 TEMP 表仅对一个会话可见,并在会话结束时“消亡”。您可以随时创建和销毁它们,但在这种情况下您应该注意内存使用情况。

希望对你有帮助。

【讨论】:

  • 我每隔一小时左右就会清理一次罢工表,这个表增长得非常快,而且该站是一个包含大约 5000 条记录的小表,其中包含点和折线。罢工不断从服务中传来,因此我每 15 秒运行一次此查询以查找最近 15 秒内受罢工影响的电台。不确定在这种情况下如何使用 tamp 表或物化视图。
  • 好吧,我不知道你的数据库结构,但是物化视图的想法是减少查询中的处理并将其添加到插入中。因此,您可以创建一个触发器,将特定数据插入到这个“物化”表中,这样查询就只能以“SELECT st.id FROM view_standar st WHERE date > (current_timestamp - interval '20 seconds')”结束。查询的处理成本几乎为零。此外,为这个物化表使用不同的表空间也会有助于更快地访问数据。
  • 顺便说一下,如果您经常删除行,您应该定期清理您的表。如果你这样做,干得好。如果不是,可能是查询执行时间较短的一个因素。
  • 我做真空,数据库一直很真空。
【解决方案2】:

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

如果这不能加快速度,您可以在 Station 多边形上引入额外的索引。

【讨论】:

    【解决方案3】:

    我会尝试通过减少可能的匹配来减少可能代价高昂的函数 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 ,以防止在连接期间进行计算。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-01-21
      • 1970-01-01
      • 1970-01-01
      • 2013-11-27
      • 2017-03-17
      • 2013-01-01
      • 1970-01-01
      • 2017-07-30
      相关资源
      最近更新 更多