使用语句超时控制失控Postgres查询

2020-06-17 09:27:56

对数据库的大多数查询都是短暂的。无论您是要为用户插入新记录还是查询即将执行的任务列表,您通常都不会聚合数百万条记录或将数千行返回给最终用户。Postgres中典型的短期查询可以在几毫秒或更短的时间内轻松完成。对于典型的应用程序,这意味着一个调优良好的生产Postgres数据库能够在一个健壮的实例上每秒轻松运行数千次或多达数十万次查询。

但是,等待的查询可能会让所有崩溃的事情都变得不堪一击。我太频繁地经历过这些经历,而且(不愿承认)有时我也是问题的起因。运行时间过长的查询通常会产生一些级联效应,最常见的情况是这些查询采用以下四种形式之一:

扫描大量记录并执行某些聚合的密集BI/Reporting查询。

原本不打算作为报告查询的错误查询,但现在正在连接数百万条记录。

上面的每个查询都可能扫描大量记录,并在数据库中混洗缓存。它甚至可能在排序数据时从内存溢出到磁盘.。这可能与持有一些锁一样糟糕,因此无法写入新数据(情况并不总是如此,但可能会发生)。即使没有持有锁,如果配置不正确,长时间运行的查询也会在复制副本上创建延迟。

这个故事的简短寓意是,当你故意做上述任何一件事时,都要谨慎行事。对于BI/Reporting查询,最好针对读取副本运行它们,以免影响生产。对于迁移,将步骤拆分成可以增量运行的较小位。但是,您如何确保上面的一些事情不会意外发生在某个不耐烦的开发人员(在这种情况下是过去版本的我)。

Postgres允许您设置数据库超时。您可以在多个级别进行设置:

为数据库设置默认语句超时是一个很好的起点。这可以确保默认情况下连接到数据库的任何应用程序或人员的查询运行时间不会超过该时间。正常的默认值是30秒或60秒:

现在,您可能希望在这60秒的时间范围内完成大部分交易。但是,仍然可能存在其他长时间运行的事务的情况-例如,确实需要更新大量数据的有意长时间运行的BI查询或迁移。对于这些特定案例,您可以有意更新您所在的会话:

就我个人而言,我发现自己在设置时最常用的是秒和分钟。但您仍然可以在任意数量的选项中选择更小或更大的选项:";us";、";ms";、";s";、";min";、";h";和";d";。

您可能需要配置的另一项内容是`idlein_transaction`的超时时间。这对于到数据库的任何连接都很有帮助,这些连接可能持有事务,但当时并未实际执行工作。在您的数据库中看到空闲事务本身并不是坏事,但是您不希望它们停留的时间比预期的更长。

如果您还没有设置Statement_TIMEOUT,请立即开始。这只是正确调优之外的又一部分,它将有助于确保您的数据库保持健康和可用。