【问题标题】:Postgres foreign wrapper and SELECT * WHERE ... performancePostgres 外部包装器和 SELECT * WHERE ... 性能
【发布时间】:2021-10-14 01:16:39
【问题描述】:

在 Postgres 服务器 A 上,我正在调用一个查询,该查询使用来自服务器 B 的外部表(来自 mav4_gmd_data):

EXPLAIN ANALYZE VERBOSE 
            SELECT 
                d.mgd_mav4_gmd_object_mgo_id, 
                d.mgd_creation_date_iso,  
                d.mgd_data
            FROM mav4_gmd_data AS d
            WHERE 
                d.mgd_creation_date_iso > '2021-08-5 10:00' AND 
                d.mgd_mav4_gmd_object_mgo_id IN (
                    SELECT pg.mgo_id
                    FROM mav4_gmd_object as pg
                    WHERE pg.mgo_class = 'Ibc' 
            )

此查询需要很长时间。查询规划器显示Server B上的SELECT(public.mav4_gmd_data上的Foreign Scan)需要8550ms(public.mav4_gmd_data上的Foreign Scan)

QUERY PLAN                                                                                                                                                                                           |
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
Hash Semi Join  (cost=235.92..266.63 rows=17 width=56) (actual time=8572.409..8572.412 rows=0 loops=1)                                                                                               |
  Output: d.mgd_mav4_gmd_object_mgo_id, d.mgd_creation_date_iso, d.mgd_data                                                                                                                          |
  Hash Cond: (d.mgd_mav4_gmd_object_mgo_id = pg.mgo_id)                                                                                                                                              |
  ->  Foreign Scan on public.mav4_gmd_data d  (cost=100.00..129.62 rows=341 width=56) (actual time=24.787..8550.000 rows=135856 loops=1)                                                             |
        Output: d.mgd_id, d.mgd_creation_date_iso, d.mgd_creation_date_unix, d.mgd_mav4_gmd_system_mgs_id, d.mgd_mav4_gmd_object_mgo_id, d.mgd_data                                                  |
        Remote SQL: SELECT mgd_creation_date_iso, mgd_mav4_gmd_object_mgo_id, mgd_data FROM public.mav4_gmd_data WHERE ((mgd_creation_date_iso > '2021-08-05 10:00:00+02'::timestamp with time zone))|
  ->  Hash  (cost=135.80..135.80 rows=10 width=16) (actual time=0.761..0.762 rows=51 loops=1)                                                                                                        |
        Output: pg.mgo_id                                                                                                                                                                            |
        Buckets: 1024  Batches: 1  Memory Usage: 11kB                                                                                                                                                |
        ->  Foreign Scan on public.mav4_gmd_object pg  (cost=100.00..135.80 rows=10 width=16) (actual time=0.744..0.751 rows=51 loops=1)                                                             |
              Output: pg.mgo_id                                                                                                                                                                      |
              Remote SQL: SELECT mgo_id FROM public.mav4_gmd_object WHERE ((mgo_class = 'Ibc'::text))                                                                                                |
Planning Time: 0.164 ms                                                                                                                                                                              |
Execution Time: 8573.195 ms                                                                                                                                                                          |

但是,如果我直接在服务器 B 上运行相同的子查询,

EXPLAIN ANALYZE VERBOSE
SELECT mgd_creation_date_iso, mgd_mav4_gmd_object_mgo_id, mgd_data FROM public.mav4_gmd_data WHERE ((mgd_creation_date_iso > '2021-08-05 10:00:00+02'::timestamp with time zone))

它的运行速度明显更快(100 毫秒):

QUERY PLAN                                                                                                                                                        |
------------------------------------------------------------------------------------------------------------------------------------------------------------------+
Index Scan using idx_mgd_mgd_creation_date_iso on public.mav4_gmd_data  (cost=0.43..16638.90 rows=42119 width=695) (actual time=0.021..96.663 rows=136032 loops=1)|
  Output: mgd_creation_date_iso, mgd_mav4_gmd_object_mgo_id, mgd_data                                                                                             |
  Index Cond: (mav4_gmd_data.mgd_creation_date_iso > '2021-08-05 10:00:00+02'::timestamp with time zone)                                                          |
Planning Time: 0.147 ms                                                                                                                                           |
Execution Time: 103.860 ms                                                                                                                                        |

对于较大的数据集,总时间的差异更为显着。 我还尝试修改 fetch_size 和 use_remote_estimate 参数,但没有任何成功。 可能是外部包装器没有使用服务器 B 上的索引吗?还有什么可能导致这个问题?还是 Postgres 的限制?

(PostgreSQL 13.3)

【问题讨论】:

    标签: postgresql performance sql-execution-plan foreign-data-wrapper


    【解决方案1】:

    使用EXPLAIN ANALYZE,它确实需要执行查询,但它需要对结果做的就是计算有多少行。但是对于 fdw,它必须在外部执行查询,格式化数据以进行传输,实际上将其推送到网络(或至少通过 IPC)然后解析出来(至少足以识别行边界)然后计算行数。

    您可以预期 fdw 比直接执行它要慢,但您的测试不一定是现实的,因为它会慢多少。如果您不想对结果做某事,大概不会运行查询,并且对结果做一些不平凡的事情会比较慢的查询按比例增加更多的时间。

    对于更真实的测试,您可以执行以下操作:

    COPY (<query>) to '/dev/null';
    

    还有时间。

    更好的是,实际上对结果进行任何处理,无论您想对最初促使您编写查询的结果做什么。

    可能是外部包装器没有使用服务器 B 上的索引吗?

    我认为没有任何理由认为会出现这种情况(毕竟,“远程 SQL”行确实显示了可索引条件正在传递下去)。但是猜测什么时候可以真正看到是没有意义的。不幸的是,EXPLAIN ANALYZE 的输出不是递归到外部的,但幸运的是,如果您控制外部服务器,您可以在外部服务器端设置 auto_explain 以捕获计划,然后从日志文件中获取关于它是什么的直接证据做。

    【讨论】:

    • 确实,很有趣。如果我更改了对源数据库的查询,确实需要更多时间。尽管如此,在目标数据库上,查询几乎花费了两倍的时间。两个数据库都在同一台机器上运行,但是正确,至少 IPC 必须发生,加上进一步的开销。 auto_explain 没有捕捉到远程查询,尽管我通过 shared_preload_libraries 全局启用了它。
    猜你喜欢
    • 2018-04-22
    • 1970-01-01
    • 2019-01-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多