我可以在多个查询中拆分查询或创建并行性来加速查询吗?

Jua*_*eza 9 c# sql postgresql performance multithreading

我有一张桌子avl_pool,我有一个功能,可以在地图上找到离该(x, y)位置最近的链接.

该选择的性能非常线性,该功能需要~8 ms才能执行.因此,计算此行选择1000行需要8秒.或者,正如我在此示例中所示,20.000行需要162秒.

SELECT avl_id, x, y, azimuth, map.get_near_link(X, Y, AZIMUTH)
FROM avl_db.avl_pool         
WHERE avl_id between 1 AND 20000

"Index Scan using avl_pool_pkey on avl_pool  (cost=0.43..11524.76 rows=19143 width=28) (actual time=8.793..162805.384 rows=20000 loops=1)"
"  Index Cond: ((avl_id >= 1) AND (avl_id <= 20000))"
"  Buffers: shared hit=19879838"
"Planning time: 0.328 ms"
"Execution time: 162812.113 ms"
Run Code Online (Sandbox Code Playgroud)

使用pgAdmin我发现如果同时在分离的窗口上执行一半的范围,执行时间实际上被分成两半.所以看起来服务器可以毫无问题地处理对同一个表/函数的多个请求.

-- windows 1
SELECT avl_id, x, y, azimuth, map.get_near_link(X, Y, AZIMUTH)
FROM avl_db.avl_pool         
WHERE avl_id between 1 AND 10000 

Total query runtime: 83792 ms.

-- windows 2
SELECT avl_id, x, y, azimuth, map.get_near_link(X, Y, AZIMUTH)
FROM avl_db.avl_pool         
WHERE avl_id between 10001 AND 20000

Total query runtime: 84047 ms.
Run Code Online (Sandbox Code Playgroud)

那么我该如何应对这种情况以提高性能呢?

C#aproach我想我可以创建多个线程,每个线程发送一部分范围,然后我加入客户端中的所有数据.所以相反,一个查询有20k和162秒,我可以发送10行查询2000行,并在~16秒内完成.当然,在连接中可能存在开销成本,但与160秒相比不应该很大.

或者我应该考虑一个不同的方法,如果只是一个简单的SQL解决方案更好?


@PeterRing我不认为功能代码是相关的,但无论如何这里是.

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 || ')';
    RAISE DEBUG 'GetLink strPoint % -- Azim %', strPoint, Azim;

    WITH index_query AS (
        SELECT --Seg_ID,
               Link_ID,
               azimuth,
               TRUNC(ST_Distance(ST_GeomFromText(strPoint,4326), geom  )*100000)::INTEGER AS distance,
               sentido,
               --ST_AsText(geom),
               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;

    RAISE DEBUG 'GetLink distance % ', sRow.distance;
    IF sRow.distance > 50 THEN
        sRow.link_id = -1;
    END IF;

    RETURN sRow;
  END;
$BODY$
  LANGUAGE plpgsql IMMUTABLE
  COST 100;
ALTER FUNCTION map.get_near_link(NUMERIC, NUMERIC, NUMERIC)
  OWNER TO postgres;
Run Code Online (Sandbox Code Playgroud)

Chr*_*ers 0

我曾经做过这样的事情。效果相对较好。请注意,每个连接一次只能处理一个查询,因此对于查询的每个分区,您必须有一个单独的连接。现在,在 C# 中,您可以使用线程与每个连接进行交互。

但另一种选择是使用异步查询并让单个线程管理和轮询整个连接池(这有时会简化应用程序端的数据操作)。请注意,在这种情况下,您最好确保每个轮询周期后都有一个睡眠或其他屈服点。

进一步请注意,查询速度的加快程度取决于您的磁盘 I/O 子系统和 CPU 并行性。因此,您不能只是抛出更多查询片段并期望加速。