我的远程 Postgres 查询似乎永远挂起

Posted

技术标签:

【中文标题】我的远程 Postgres 查询似乎永远挂起【英文标题】:My remote Postgres query seems to hang forever 【发布时间】:2018-10-12 02:55:56 【问题描述】:

我正在从本地客户端对远程 Postgres 实例运行以下查询:

select * from matches_tb1 order by match_id desc limit 10;

matches_tb1 是一个外部表,并以 match_id 作为唯一索引。查询似乎永远挂起。当我使用explain verbose 时,没有ORDER BY 附加到“远程SQL”。我猜本地服务器没有将订单下推到远程服务器。我该如何解决这个问题?

附上解释结果:

 explain verbose select match_id from matches_tb1 order by match_id desc limit 10;
                                            QUERY PLAN                                             
---------------------------------------------------------------------------------------------------
 Limit  (cost=33972852.96..33972852.98 rows=10 width=8)
   Output: match_id
   ->  Sort  (cost=33972852.96..35261659.79 rows=515522734 width=8)
         Output: match_id
         Sort Key: matches_tb1.match_id DESC
         ->  Foreign Scan on public.matches_tb1  (cost=100.00..22832592.02 rows=515522734 width=8)
               Output: match_id
               Remote SQL: SELECT match_id FROM public.matches_tb1
(8 rows)

【问题讨论】:

请在您的问题中发布完整的EXPLAIN 查询计划。 附加解释详细结果 计划中提到match_id 被用作排序键,所以我看不出有什么意外。您是否可以尝试其他任何查询,以便我们查看其他情况下是否存在此延迟问题? sql_1 = select match_id from matches_tb1 where match_id > 4164287140 order by match_id desc limit 10; sql_2 = 从matches_tb1 中选择match_id,其中match_id > 416428 order by match_id desc limit 10;我可以很快得到 sql_1 的结果,但是 sql_2 永远挂起。如果这些 sqls 直接在远程服务器上执行(而不是通过 postgres_FDW),则两者都可以在一秒钟内结束。 我收回我上面说的话。 match_id 索引似乎没有被使用。结果,Postgres 是手动对整个 5 亿条记录表进行排序,只为找到前 10 条记录。所以,我们需要想办法让索引生效。你确定match_id上面有一个B树索引吗? 【参考方案1】:

对于您问题中的第一个查询:

select * from matches_tb1 order by match_id desc limit 10;

根据EXPLAIN 计划,Postgres 似乎没有使用match_id B-tree 索引。这导致查询很长,因为数据库必须扫描整个 5 亿条记录表并排序,才能找到 10 条记录。至于为什么 Postgres 不能使用索引,问题是select *。当数据库到达索引中每个条目的叶子节点时,它只会找到match_id 的值。但是,由于您正在执行select *,因此数据库必须查找聚集索引以查找所有其他列的值。如果您的表的相关性较低,那么优化器可能会选择完全放弃索引而只对表进行全盘扫描。

相比之下,请考虑您的其他一个执行速度很快的查询:

select match_id from matches_tb1 where match_id > 4164287140
order by match_id desc limit 10

在这种情况下,可以使用match_id 上的索引,因为您只选择了match_id。此外,where 子句中的限制更有助于使索引更加具体。

因此,如果您希望查询快速完成,则此处解决您的问题的方法是不要将 select *limit 一起使用。例如,如果您只想从表中说出两列 col1col2,那么您可以将这些列添加到索引中以覆盖它们。那么,下面的查询也应该很快:

select match_id, col1, col2 from matches_tb1 order by match_id desc limit 10;

【讨论】:

首先感谢您的回复。外部表有 5 亿行。当我直接连接到远程服务器时,我可以在几秒钟内得到结果。但是当我使用 FDW 时,我无法获得结果(永远挂起)。所以我假设 order by 没有推送到远程服务器。 实际上,您看到的延迟似乎表明 正在为LIMIT 子句进行排序步骤。 对不起,我没明白你的意思。我假设我的查询永远挂起,因为本地服务器尝试从外部表中获取所有数据(5 亿)并在本地进行排序。如果 order by 在远程服务器上完成,那么我也应该在一秒钟内看到结果。 如果你在远程运行查询,那么整个事情应该在远程运行。如果您建议 Postgres 通过网络返回 5 亿条记录,然后您在本地执行 ORDER BY,我完全不会想到会这样。 要点是我不想在本地执行 ORDER BY,我希望在远程服务器上执行 ORDER BY,但据我所见 ORDRE BY 并没有在远程服务器上执行。如果确实如此,为什么我的查询会永远挂起?

以上是关于我的远程 Postgres 查询似乎永远挂起的主要内容,如果未能解决你的问题,请参考以下文章

批量插入在 docker 容器中运行的 Postgres 数据库挂起

Postgres.app:pg_restore 挂起

Virtualenv 和 Pip 永远挂起

PyCharm 3.1 在索引期间永远挂起并且无法使用

启动远程程序时出错:正在启动或挂起

如何结束 mysql 连接而不让它挂在 NodeJS 中?