簡體   English   中英

ST_DWithin優化多個SRID

[英]ST_DWithin optimization for multiple SRIDs

在我的PostgreSQL 9.3數據庫中,我有一個名為location的表,其中包括一個用於存儲POINT幾何的coordinate列。 這些點是使用SRID 4326創建的。在某些情況下,我們將這些坐標ST_Transform轉換為SRID 900913,以使用米為單位的距離對其進行過濾。

例如,要使用ST_WDithin查找坐標在給定坐標10000米以內的所有位置,查詢如下所示:

SELECT *
FROM LOCATION 
WHERE ST_DWithin(ST_Transform(location.coordinate, 900913), ST_Transform(ST_GeomFromText('POINT(-74.005941 40.712784)', 4326), 900913), 10000)
ORDER BY ST_Distance_Sphere(location.coordinate, ST_GeomFromText('POINT(-74.005941 40.712784)', 4326))
LIMIT 100

該語句的查詢計划如下所示:

Limit  (cost=19207.98..19208.23 rows=100 width=36)
  ->  Sort  (cost=19207.98..19209.81 rows=729 width=36)
        Sort Key: (_st_distance(geography(coordinate), '0101000020E6100000282D5C56618052C0588E90813C5B4440'::geography, 0::double precision, false))
        ->  Seq Scan on location  (cost=0.00..19180.12 rows=729 width=36)
              Filter: ((st_transform(coordinate, 900913) && '010300002031BF0D000100000005000000D42FBDEAFB765FC187C3AD4ED1EB5241D42FBDEAFB765FC187C3AD4E59FF5241D42FBDEA73635FC187C3AD4E59FF5241D42FBDEA73635FC187C3AD4ED1EB5241D42FBDEAFB765FC187C3AD4ED1EB5241'::geometry) AND ('010100002031BF0D00D42FBDEA376D5FC187C3AD4E95F55241'::geometry && st_expand(st_transform(coordinate, 900913), 10000::double precision)) AND _st_dwithin(st_transform(coordinate, 900913), '010100002031BF0D00D42FBDEA376D5FC187C3AD4E95F55241'::geometry, 10000::double precision))

這可以,但是非常慢。 涉及的所有坐標都轉換為SRID 900913,從而可以在米中工作。 通過測試,我發現刪除ST_Transform可以大大加快此查詢的速度。

我還嘗試了使用ST_Buffer創建圓形POLYGON,然后進行測試以查看location.coordinate是否與此多邊形相交。 為此,我將輸入坐標ST_Transform轉換為SRID 900913,使用ST_Buffer繪制一個半徑為米的圓,然后將該多邊形ST_Transform轉換為SRID 4326以與我的位置表中的坐標進行比較。 查詢如下所示:

SELECT *
FROM LOCATION 
WHERE location.coordinate && ST_Transform(ST_Buffer(ST_Transform(ST_GeomFromText('POINT(-74.005941 40.712784)', 4326), 900913), 10000), 4326))
ORDER BY ST_Distance_Sphere(location.coordinate, ST_GeomFromText('POINT(-74.005941 40.712784)', 4326))
LIMIT 100

在我的測試中,第二個查詢的運行速度比第一個查詢快得多。 它的運行速度甚至比我使用ST_DWithin減去ST_Transform的查詢版本要快一些。 從我看過的所有內容來看,似乎ST_DWithin應該是執行此類搜索的最快方法。 該問題的答案表明,我應該能夠為轉換為不同SRID的坐標創建索引: 使用st_transform,st_makepoint和st_contains的PosgtreSQL優化查詢

我通過運行以下方法進行了嘗試:

CREATE INDEX idx_location_coordinate_900913
 ON LOCATION
 USING gist
 (ST_Transform(coordinate, 900913))
 WHERE coordinate IS NOT NULL;

創建此索引后,在運行原始查詢時,我發現速度沒有任何提高。 我發現奇怪的是,此命令很快就成功完成,並且重建索引很快就發生了。 位置表中有成千上萬的行,因此我想創建此索引將是一個耗時的過程。 我創建不正確嗎?

轉換點時,我可以做些什么來加快ST_DWithin的速度嗎? 我的方法是否存在重大缺陷?

編輯:我正在為上面的初始查詢添加執行計划。

我建議在PostgreSQL中創建一個函數來處理從米到十進制的轉換。 通過這樣做,您可以避免轉換每行,而ST_DWithin函數在本機投影中起作用。

您需要仔細檢查數學,我建議將結果與使用ST_Transform進行比較,但是我敢肯定,這已經很接近了。 我使用的功能通常使用英里而不是米,但是我很快就添加了米換算。

在該函數中,值3960是地球直徑的估計值,而1609.34的句柄從英里變為米。 我不保證這與ST_Transform一樣精確,但由於不必轉換每一行,因此它應該會更好地提高性能。

CREATE FUNCTION meters_to_decimal_degrees(meters double precision)
RETURNS double precision AS
$BODY$
    SELECT (($1 * 180 * 1609.34) / ( 3960 * pi() ) ) AS decimal_degrees
$BODY$
LANGUAGE sql IMMUTABLE SECURITY DEFINER
;


ALTER FUNCTION public.meters_to_decimal_degrees(double precision) SET search_path=public, pg_temp;

這樣,您的查詢可以更改為:

SELECT *
    FROM LOCATION 
    WHERE ST_DWithin(location.coordinate, ST_GeomFromText('POINT(-74.005941 40.712784)', 4326), meters_to_decimal_degrees(10000))
    ORDER BY ST_Distance_Sphere(location.coordinate, ST_GeomFromText('POINT(-74.005941 40.712784)', 4326))
    LIMIT 100

希望有幫助。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM