如何通过太慢的 SQL 查询来优化计数/分组

问题描述 投票:0回答:2

我目前正在开发具有多个操作的 SOAP 服务。请求和响应保存在名为“消息”的表中。每个请求和每个响应在表中都有自己的条目,每个请求/响应对都有一个相应的correlation_id。

我创建了一个 SELECT 查询来显示过去 15 分钟内每个操作被使用的次数:

SELECT operation,
       count(distinct (correlation_id)) as last_15_minutes
FROM message
WHERE creation_timestamp > (SELECT NOW() - INTERVAL '15 MINUTES')
GROUP BY operation ;

此查询有效。当我运行它时,我得到以下正确结果:

operation last_15_minutes      
--------- -------------------- 
5001      17                   
5005      15                   
5013      2                    
5021      7602                 
5201      4    

问题是查询速度极慢。当过去 15 分钟内发送了很多请求时,上述结果可能需要超过 30 秒。

有人知道什么可以改进吗?

提前谢谢您。

编辑:

这是创建此表的脚本:

CREATE TABLE message
(
  id bigint GENERATED BY DEFAULT AS IDENTITY (INCREMENT 1 START 10000000 MINVALUE 1 MAXVALUE 9223372036854775807) PRIMARY KEY,
  correlation_id character varying(50) not null,
  operation character varying(4),
  variant character varying(4),
  status bigint,
  message character varying,
  creation_timestamp timestamp without time zone not null,
  version bigint not null
);

这是我在这张桌子上的索引

CREATE INDEX message_creation_timestamp_idx ON message USING btree (creation_timestamp)
CREATE INDEX message_creation_timestamp_operation_variant_idx ON message USING btree (creation_timestamp, operation, variant)

这是 EXPLAIN (ANALYZE, VERBOSE, BUFFERS) 的结果:

解释结果

sql postgresql group-by count query-optimization
2个回答
0
投票

此查询速度很慢,因为没有有用的索引,而且统计数据相差甚远:数据库预计有 530 万条记录,但只找到 7 行。

首先创建这些索引之一,或尝试所有索引:

CREATE INDEX message_creation_timestamp_operation_idx ON message USING btree (creation_timestamp, operation);

CREATE INDEX message_creation_timestamp_operation_correlation_id_idx ON message USING btree (creation_timestamp, operation, correlation_id);

CREATE INDEX message_creation_timestamp_operation_correlation_id_2_idx ON message USING btree (creation_timestamp, operation) INCLUDE (correlation_id);

还运行 ANALYZE 以获取最新的统计信息,并检查 autovacuum 进程。因为该过程还会进行自动分析。

创建索引后,再次检查查询计划。

SELECT operation,
       count(distinct correlation_id) as last_15_minutes
FROM message
WHERE creation_timestamp > (NOW() - INTERVAL '15 MINUTES')
GROUP BY operation;

0
投票

问题不在于索引,而在于每次都重新计算条件。通过从Where子句中删除“SELECT”,查询速度实际上可以降低到千分之几...

© www.soinside.com 2019 - 2024. All rights reserved.