You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

PostgreSQL(PostGIS)查询远慢于MySQL,求原因及优化方向

百万级数据下PostgreSQL与MySQL地理查询性能差异排查问题

对包含约百万条数据的PostgreSQL(PGSQL)和MySQL数据库开展性能测试后,发现MySQL的查询执行速度明显更快,但预期应是PostgreSQL表现更优,推测遗漏了关键优化点。

分别测试了使用和不使用PostGIS函数(如ST_DistanceSphere)的经纬度距离计算查询,结果显示使用PostGIS函数的查询速度更慢,这与PostGIS应更高效的预期不符。已为PGSQL中的geom(geometry)字段创建索引,但查询仍仅执行顺序扫描,即便仅返回数据库中5-10%的数据。

两个数据库数据完全一致,以下是各查询语句、执行时间及执行计划分析:


PostgreSQL 查询测试

Query 1 PGSQL(最快,未使用PostGIS函数)

WITH users_filtered AS (
SELECT id, pseudonym, city, (6371 * acos( 
                cos( radians(users.latitude) ) 
              * cos( radians( 49.5099 ) ) 
              * cos( radians( 6.74549 ) - radians(users.longitude) ) 
              + sin( radians(users.latitude) ) 
              * sin( radians( 49.5099 ) )
        ) ) as distance_in_km
FROM users
)
SELECT * FROM users_filtered;

执行计划与时间:

Seq Scan on users  (cost=0.00..124501.90 rows=1029033 width=29) (actual time=0.032..932.905 rows=1030000 loops=1)
  Buffers: shared hit=80768
Planning:
  Buffers: shared hit=361
Planning Time: 1.697 ms
Execution Time: 984.460 ms

Query 2 PGSQL(最慢,使用PostGIS函数)

WITH users_filtered AS (
SELECT id, pseudonym, city, ST_DistanceSphere(
    CAST(point(49.5099, 6.74549) AS geometry),
    users.geom
) AS distance_in_m
FROM users
)
SELECT * FROM users_filtered;

执行计划与时间:

Gather  (cost=1000.00..10909130.85 rows=1029033 width=29) (actual time=3.739..2583.961 rows=1030000 loops=1)
  Workers Planned: 2
  Workers Launched: 2
  Buffers: shared hit=81778
  ->  Parallel Seq Scan on users  (cost=0.00..10805227.55 rows=428764 width=29) (actual time=2.096..2147.072 rows=343333 loops=3)
        Buffers: shared hit=81778
Planning:
  Buffers: shared hit=19
Planning Time: 0.577 ms
Execution Time: 2696.416 ms

Query 3 PGSQL(中等,使用PostGIS函数)

WITH users_filtered AS (
    SELECT id, pseudonym, city, ST_DistanceSphere(
        CAST(point(49.5099, 6.74549) AS geometry),
        users.geom
    ) AS distance_in_m
    FROM users
    WHERE ST_DWithin(users.geom, ST_SetSRID(ST_MakePoint(49.5099, 6.7454),4326), 200000)
)
SELECT * FROM users_filtered;

执行计划与时间:

Gather  (cost=1000.00..10806234.80 rows=103 width=29) (actual time=1.526..2071.394 rows=1030000 loops=1)
  Workers Planned: 2
  Workers Launched: 2
  Buffers: shared hit=81674
  ->  Parallel Seq Scan on users  (cost=0.00..10805224.50 rows=43 width=29) (actual time=1.336..1752.659 rows=343333 loops=3)
        Filter: st_dwithin(geom, '0101000020E61000007E1D386744C14840ECC039234AFB1A40'::geometry, '200000'::double precision)
        Buffers: shared hit=81674
Planning:
  Buffers: shared hit=23
Planning Time: 1.169 ms
Execution Time: 2161.133 ms

MySQL 查询测试

Query 1 MySQL(最快,相同查询在PGSQL需4-5秒)

SELECT id, pseudonym, city, ROUND(111.045 *
          degrees(acos(cos(radians(49.5099)) *
          cos(radians(users.latitude)) *
          cos(radians(6.74549) -
          radians(users.longitude)) +
          sin(radians(49.5099)) *
          sin(radians(users.latitude)
          )
        )
      )
    ) AS distance_in_km FROM users;

执行计划与时间:

-> Table scan on users  (cost=272574.70 rows=2515667) (actual time=0.121..1023.582 rows=1030000 loops=1)

Query 2 MySQL(最慢,使用ST_Distance_Sphere)

SELECT id, pseudonym, city, ST_Distance_Sphere(
    point(49.5099, 6.74549),
    point(users.latitude, users.longitude)
) AS distance_in_m FROM users;

执行计划与时间:

-> Table scan on users (cost=272574.70 rows=2515667) (actual time=0.096..1073.000 rows=1030000 loops=1)

Query 3 MySQL(中等)

SELECT id, pseudonym, city, (6371 * acos( 
                cos( radians(users.latitude) ) 
              * cos( radians( 49.5099 ) ) 
              * cos( radians( 6.74549 ) 
              - radians(users.longitude) ) 
              + sin( radians(users.latitude) ) 
              * sin( radians( 49.5099 ) )
        ) ) as distance_in_km
FROM users ORDER BY distance_in_km ASC;

执行计划与时间:

-> Sort: (6371 * acos((((cos(radians(users.latitude)) * cos(radians(49.5099))) * cos((radians(6.74549) - radians(users.longitude)))) + (sin(radians(users.latitude)) * sin(radians(49.5099))))))  (cost=272574.70 rows=2515667) (actual time=2142.974..2268.429 rows=1030000 loops=1)
    -> Table scan on users  (cost=272574.70 rows=2515667) (actual time=0.141..1003.752 rows=1030000 loops=1)

请问为何PGSQL比MySQL慢这么多,尤其是使用PostGIS函数时?希望能得到排查方向的指引。

内容的提问来源于stack exchange,提问作者Romek

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.05 12:11:04