【发布时间】: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) 是的,有空间索引,
<->查找近链接的速度很快。 (3) 是的,我将搜索限制在最近的 100 个链接,然后if sRow.distance > 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 <->当地图有 600k 链接看起来并不慢时,我仍然可以在 30 秒内找到 400 条记录的near_link。可以说我下降到 10 秒,但我仍然无法扩展到 +1200 记录/分钟。所以我需要做点别的事情
标签: sql algorithm postgresql function scalability