如何在 postgresql 中改进此查询?它已经花费了超过 48 小时

Posted

技术标签:

【中文标题】如何在 postgresql 中改进此查询?它已经花费了超过 48 小时【英文标题】:How can I improve this query in postgresql? Its taking more than 48 houers already 【发布时间】:2021-09-22 10:49:38 【问题描述】:

我确实有以下查询,我正在对一个 postgresql 数据库运行它,该数据库在表 account_message 中有超过 10M 的条目,在表 message 中有超过 1M 的条目。

Postgresql 的版本为PostgreSQL 11.12, compiled by Visual C++ build 1914, 64-bit

有什么办法可以让这个查询更快,因为它已经花费了超过 2 天而且还没有完成。

DELETE FROM account_message WHERE message_id in
(SELECT t2.id FROM message t2 WHERE NOT EXISTS 
(SELECT 1 FROM customer t1 WHERE 
t1.username = t2.username));

account_message 具有以下列:

id (bigint)(primary key)
user_id (bigint)
message_id (bigint)
isRead (boolean)
isDeleted (boolean)

message 具有以下列:

id (bigint)(primary key)
username (character varying)(255)
text (character varying)(10000)
details(character varying)(1000)
status(integer)

customer 具有以下列:

username (character varying)(255)(primary key)
type(character varying)(500)
details(character varying)(10000)
status(integer)
active(boolean)

这对我有用,而且速度更快。

DELETE FROM account_message WHERE message_id IN (
  SELECT m.id FROM message m
    LEFT JOIN customer c ON m.username = c.username
    WHERE c.username IS NULL LIMIT 1000)

【问题讨论】:

您的表是否有适当的索引,即message_idusername 我如何检查这个?例如使用 pgAdmin。 我会尝试这样的事情:select * from pg_indexes where lower(tablename) in ('account_message', 'message', 'customer'); 请read this 然后edit 向我们展示您的表定义和查询计划。 尝试将IN (SELECT ...)转换成EXISTS (SELECT ...) 【参考方案1】:

您可以通过以下方式改进这一点

    摆脱依赖的子查询,并且 分批进行。

尝试此操作以获取一批要删除的一千个消息 ID。 LEFT JOIN ... WHERE col IS NULL 是一种编写 WHERE NOT EXISTS 的方式,无需依赖子类。

SELECT m.id 
  FROM message m
  LEFT JOIN customer c ON m.username = c.username
 WHERE c.username IS NULL
 LIMIT 1000

然后,在语句中使用子查询。重复该语句,直到它不删除任何行。

DELETE 
  FROM account_message
 WHERE message_id IN (
      SELECT m.id 
        FROM message m
        LEFT JOIN customer c ON m.username = c.username
       WHERE c.username IS NULL
       LIMIT 1000)

以 1000 个批量执行此操作有助于提高性能:它将您的操作拆分为多个大小合理的数据库事务。

【讨论】:

当以 1000 个批次执行此操作时,它们何时准确执行?我确实在飞行脚本中运行它。所以通常每个像这里这样的脚本只执行一次。我必须自己管理吗?【参考方案2】:

首先,尝试优化括号内的选择。比如:

DELETE FROM account_message WHERE message_id in
(
  select t2.id message t2
  left join customer t1 on (t1.username = t2.username)
  where t2.username is NULL
)

【讨论】:

为什么应该更快? @LaurenzAlbe 消除依赖子查询有可能使其更快。 @O.Jones PostgreSQL 通常将NOT EXISTS 优化为反连接。根据我的经验,它的表现通常优于 IN (SELECT ...)

以上是关于如何在 postgresql 中改进此查询?它已经花费了超过 48 小时的主要内容,如果未能解决你的问题,请参考以下文章

为子查询优化 Postgresql 查询

如何改进此 LINQ 查询以查找用户将列表中的所有技能

如何在 PostgreSQL 9.2.13 中执行 *此特定 * 更新 + 加入?

PostgreSQL9.6新功能

如何提高此 PostgreSQL 查询在索引扫描中的性能

SQL 查询非常慢 - 我该如何改进它?