我遇到了我无法解释的问题,并且已经搜索了几天,并且尚未发现PostgresQL计划程序导致我的“问题”的原因,导致(相对简单的)查询占用了大量的时间。
让我们从头开始(我试图删除尽可能多的无用信息,以使表看起来毫无意义,但请相信我,不是):
我有以下架构:
CREATE TABLE ct_log (
ID integer,
CONSTRAINT ctl_pk
PRIMARY KEY (ID)
);
CREATE TABLE ct_log_entry (
CERTIFICATE_ID bigint NOT NULL,
ENTRY_ID bigint NOT NULL,
ENTRY_TIMESTAMP timestamp NOT NULL,
CT_LOG_ID integer NOT NULL,
CONSTRAINT ctle_ctl_fk
FOREIGN KEY (CT_LOG_ID)
REFERENCES ct_log(ID)
) PARTITION BY RANGE (ENTRY_TIMESTAMP);
-- I will not repeat this one 7 times, but there are partition for each year from 2013-2020:
CREATE TABLE ct_log_entry_2020 PARTITION OF ct_log_entry
FOR VALUES FROM ('2020-01-01T00:00:00'::timestamp) TO ('2021-01-01T00:00:00'::timestamp);
CREATE INDEX ctle_c ON ct_log_entry (CERTIFICATE_ID);
CREATE INDEX ctle_e ON ct_log_entry (ENTRY_ID);
CREATE INDEX ctle_t ON ct_log_entry (ENTRY_TIMESTAMP);
CREATE INDEX ctle_le ON ct_log_entry (CT_LOG_ID, ENTRY_ID DESC);
(如果您对完整的架构感到好奇:https://github.com/crtsh/certwatch_db/blob/master/sql/create_schema.sql)
这是我要运行的查询:
SELECT ctl.ID, latest.entry_id
FROM ct_log ctl
LEFT JOIN LATERAL (
SELECT coalesce(max(entry_id), -1) entry_id
FROM ct_log_entry ctle
WHERE ctle.ct_log_id = ctl.id
) latest ON TRUE;
对于认识https://crt.sh的人来说,这可能看起来很熟悉,因为这确实是来自crt.sh的架构。由于crt.sh提供了public PostgresQL access,使我可以比较自己的服务器和它们自己的服务器之间的查询计划,因此这有点有趣。
这种区别非常明显(:sad_smile :),但我不确定为什么会这样,因为据我所知,我拥有正确的索引非常快,并且与crt.sh服务器具有相同的索引。
看起来我的实例正在使用向后索引扫描,而不是仅对最大的2个分区进行索引扫描。并非总是如此,并且以前它使用与crt.sh实例相同的查询计划执行,但是由于某种原因,它决定停止这样做。
(这是这些表中的数据量,以防在查询计划中不清楚:https://d.bouma.dev/wUjdXJXk1OzF。我看不到crt.sh数据库中的数据量,因为它们没有提供访问各个分区)
现在进入我尝试过的事情清单:
ANALYZE
ct_log_entry
(以及由分区创建的ct_log_entry_*
表)VACUUM ANALYZE
ct_log_entry
(以及由分区创建的ct_log_entry_*
表)VACUUM FULL
ct_log_entry
(以及由分区创建的ct_log_entry_*
表)ctle_le
索引并重新创建(这一次对我有用,给了我几个小时的性能,直到我导入了更多数据,然后又进行了向后扫描)REINDEX INDEX
在每个ctle_le
表上的ct_log_entry_*
索引SET random_page_cost = x;
,1
,1.1
,4
和5
(根据许多SO解答和博客文章)进行了尝试我唯一注意到的不同是crt.sh正在运行PostgresQL 12.1
,而我正在运行12.3
,但据我所知这不会产生任何影响。
在您说“是的,但是您不能在笔记本电脑上运行此数量的数据”之前,我正在运行的服务器是一个专用盒,具有32个可用线程和128GB RAM,并运行8个2TB的RAID 5三星EVO 860驱动器在硬件RAID上运行(是的,我知道如果驱动器发生故障,这是很糟糕的,这是我稍后要处理的另一个问题,但是读取性能应该很好)。我不知道crt.sh在硬件上运行什么,但是由于我只导入了一部分数据,所以这里还没有看到我的硬件问题。
我还使用此处的指南https://pgtune.leopard.in.ua/#/“调整”了我的配置。
很高兴在需要的地方提供更多信息,但希望有人可以指出我的缺陷和/或提供解决问题的方法,并向PostgresQL展示如何使用最佳路径!