繁体   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