如何使db进程可伸缩?

时间:2016-11-22 21:04:03

标签: sql algorithm postgresql function scalability

我的应用程序从不同来源获取 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 个答案:

答案 0 :(得分:0)

abs(Azim - S.azimuth) < 30的where子句不能使用S.azimuth上的任何索引。每个SELECT都将导致全表扫描。

如果在执行SELECT查询之前计算了有效方位角范围(或范围),则可能会出现azimuth BETWEEN low AND high之类的条件。与azimuth上的索引一起使用可以加快查询速度。