我目前正在开发具有多个操作的 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) 的结果:
此查询速度很慢,因为没有有用的索引,而且统计数据相差甚远:数据库预计有 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;
问题不在于索引,而在于每次都重新计算条件。通过从Where子句中删除“SELECT”,查询速度实际上可以降低到千分之几...