【问题标题】:How can I make a db process scalable?如何使数据库进程可扩展?
【发布时间】:2017-04-06 16:52:38
【问题描述】:

我的应用程序从不同来源获取 AVL 数据并将其合并到一个池表中。

然后我有一个函数map.get_near_link(sq.X, sq.Y, sq.AZIMUTH) 来计算与该池中每个汽车位置最近的链接。

CREATE TYPE map.get_near_link AS
   (link_id integer,
    distance integer,  -- distance to the link
    sentido integer,   -- use azimuth to know what direction of link is traveling
    geom geometry(4)); -- the link geometry

目前我每分钟收到大约 400 avl,计算所有这些的 near_link 的过程需要 10-30 秒。所以理论上我可以毫无问题地处理所有记录。但是如果源输入增加到 +800 avl/min,我将无法处理所有数据。

那么我应该采取什么措施来让我的流程处理未来数据输入量的增加。

这是我当前的进程。我设置了一个作业,每分钟运行一次。

-- new records doesnt have near_link
SELECT MAX(avl_id) INTO int_pending 
FROM   avl_db.avl_pool
WHERE  near_link IS NULL;   

-- loop while the pool isnt empty
WHILE  int_pending > 0  LOOP  
    --udpate take around 10-30 sec   
    UPDATE avl_db.avl_pool a
    SET near_link = map.get_near_link(sq.X, sq.Y, sq.AZIMUTH)
    FROM ( 
         -- this select take ~100 ms
         SELECT avl_id, x, y, azimuth
         FROM avl_db.avl_pool
         WHERE near_link IS NULL
         ORDER BY avl_id
         LIMIT 400 -- I choose 400 after some testing, 
                   -- so doesnt lock the table for too long.
        ) sq
    WHERE a.avl_id = sq.avl_id;

    -- check if pool is empty
    SELECT MAX(avl_id) INTO int_pending 
    FROM   avl_db.avl_pool
    WHERE  near_link IS NULL;       
END LOOP;

仅供参考:

avl_pool 表

CREATE TABLE avl_db.avl_pool
(
  avl_id bigserial NOT NULL,
  car_id bigint,
  hora timestamp without time zone,
  x numeric(10,6),
  y numeric(10,6),
  azimuth integer,
  speed numeric(10,3),
  near_link map.get_near_link,
  CONSTRAINT avl_pool_pkey PRIMARY KEY (avl_id)
);

这是 map.get_near_link 函数。我做了很多工作以尽量提高效率,但如果必须再次工作以减少时间可以接受建议。

CREATE OR REPLACE FUNCTION map.get_near_link(
    x numeric, y numeric, azim numeric)
  RETURNS map.get_near_link AS
$BODY$
DECLARE
    strPoint text;
    sRow map.get_near_link;
  BEGIN
    strPoint = 'POINT('|| X || ' ' || Y || ')';

    with index_query as (
        SELECT Link_ID, azimuth, 
               TRUNC(ST_Distance(ST_GeomFromText(strPoint,4326), geom  )*100000)::integer as distance, 
               sentido, geom
        FROM map.vzla_seg S
        WHERE 
            abs(Azim - S.azimuth) < 30 OR
            abs(Azim - S.azimuth) > 330
        ORDER BY 
            geom <-> ST_GeomFromText(strPoint, 4326)
        LIMIT 101
    )
    SELECT i.Link_ID, i.Distance, i.Sentido, v.geom into sRow 
    FROM 
        index_query i inner join 
        map.vzla_rto v ON i.link_id = v.link_id
    ORDER BY 
        distance limit 1;

    if sRow.distance > 50 then
        sRow.link_id = -1;
    end if;

    RETURN sRow;
  END;

【问题讨论】:

  • (1) 请添加表的 DDL + 基数 (2) 我们可以假设您已经创建了空间索引并且它们正在被优化器使用吗? (3) 我们能否假设 AVL 和相对较好的过滤器链接之间存在最大相关距离?
  • @DuduMarkovitz (1) avl_pool 增加约 400 条记录/分钟,我经常清理台球桌,所以最多大约 100k 条记录。 (2) 是的,有空间索引,&lt;-&gt; 查找近链接的速度很快。 (3) 是的,我将搜索限制在最近的 100 个链接,然后 if sRow.distance &gt; 50 then (4) 我将添加 ddl,但已经显示的不多了。 x, y, 方位角, near_link
  • ST_GeomFromText() 是做什么的?它被调用了两次,你必须为它编写一个字符串。你可以重写它来取 X 和 Y 吗?
  • abs(Azim - S.azimuth) NOT BETWEEN 30 AND 330 -- 不知道这是否有帮助 -- 取决于你的平台。
  • @Hogan geom 是来自 postgis 扩展的空间类型。该函数采用 geom_text 并转换为 geom 对象。我可以创建一个WITH parameter 来计算一次。但重的部分是select ..order &lt;-&gt; 当地图有 600k 链接看起来并不慢时,我仍然可以在 30 秒内找到 400 条记录的near_link。可以说我下降到 10 秒,但我仍然无法扩展到 +1200 记录/分钟。所以我需要做点别的事情

标签: sql algorithm postgresql function scalability


【解决方案1】:

abs(Azim - S.azimuth) &lt; 30 的 where 子句不能在 S.azimuth 上使用任何索引。每个 SELECT 都会导致一次全表扫描。

如果您在执行 SELECT 查询之前计算了有效的方位角范围(或范围),您可能会遇到类似azimuth BETWEEN low AND high 的条件。与azimuth 上的索引一起,这将加快查询速度。

【讨论】:

  • 我做不到。如果汽车在方位角 0 上行驶。方位角为 345 和 15 的道路连接方向相同。但我会再次检查那个条件
  • 您可以检查HERE &lt;-&gt; 使用空间索引找到附近的 100 个对象,然后对方位角进行过滤。所以非常高效,只需要 30 毫秒。
猜你喜欢
  • 2012-10-13
  • 1970-01-01
  • 1970-01-01
  • 2021-09-26
  • 2013-12-10
  • 2010-12-07
  • 1970-01-01
  • 2020-03-04
  • 2012-12-05
相关资源
最近更新 更多