2016-11-22 5 views
0

私のアプリケーションは、さまざまな情報源からのAVLのデータを取得し、プールテーブルにマージします。dbプロセスをスケーラブルにするにはどうすればよいですか?

次に、私はそのプール内のすべての車の位置に最も近いリンクが何であるかを計算するために関数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; 
+0

(1)テーブルのDDL +カーディナリティを追加してください。(2)空間インデックスを作成し、それらがオプティマイザで使用されていると仮定できますか? (3)AVLと相対良好フィルタであるリンクとの間に最大の関連距離があると仮定できるか? –

+0

@DuduMarkovitz(1)avl_poolは〜400レコード/分を増やします。私はプールテーブルを非常に頻繁にクリーニングします。 (2)はい、空間インデックスがあり、近くのリンクを見つけるために '<->'を多くスピードします。 (3)はい、私は最も近い100リンクに検索を制限し、 'if sRow.distance> 50 then'(4)ddlを追加しますが、これ以上は表示しません。 x、y、azimuth、near_link –

+0

'ST_GeomFromText()'は何をするのですか?それは2度呼ばれ、あなたはそれのための文字列を構成する必要があります。 XとYを取るために書き直せますか? – Hogan

答えて

0

abs(Azim - S.azimuth) < 30とwhere節はS.azimuth上の任意のインデックスを使用することはできません。各SELECTを実行すると、テーブル全体がスキャンされます。

SELECTクエリを実行する前に有効な方位範囲(または範囲)を計算した場合は、azimuth BETWEEN low AND highのような条件を設定できます。 azimuthのインデックスと一緒にすると、クエリが高速化されます。

+0

私はそれを行うことはできません。車が方位角0に向かう場合。方位角345と15の道路リンクは同じ方向にあります。しかし、もう一度その状態を確認します –

+0

[** HERE **](https://explain.depesz.com/s/Lr38)を確認できるように、 '<->'は空間インデックスを使って近くの100オブジェクトを見つけてから方位角のフィルタ。したがって、非常に効率的なのはわずか30ms必要です。 –

関連する問題