13

我有一张有 10M 行的大桌子。我需要为每一行获取一些统计值。我有生成这个值的函数,例如GetStatistic(uuid). 这个函数工作得非常慢,结果值不经常改变,所以我Statistic在我的表中创建了列,并且每天执行一次这样的查询:

UPDATE MyTable SET Statistic = GetStatistic(ID);

在选择查询中,我使用列Statistic而不调用GetStatistic函数。

问题是,我的生产服务器有 64 个 CPU 和大量内存,所以几乎所有的 DB 都可以缓存到 RAM,但是这个查询只使用一个 CPU,需要 2 或 3 个小时来执行。

GetStatistic 函数使用表,该表在所有查询执行期间都是不变的UPDATE。我可以修改查询以使 postgreGetStatistic使用所有可用的 CPU 同时并行计算不同的行吗?

4

1 回答 1

17

早于 10 的 PostgreSQL 版本在单个后端执行每个查询,该后端是具有单个线程的进程。它不能使用多个 CPU 进行查询。它在单个查询中可以实现的 I/O 并发性也有所限制,实际上只为位图索引扫描执行并发 I/O,否则依赖操作系统和磁盘系统进行并发 I/O。

PostgreSQL 10+ 支持并行查询。在撰写本文时(PostgreSQL 12 版本)并行查询仅用于只读查询。并行查询支持为某些类型的查询提供了相当多的并行性。

Pg 擅长并发负载许多较小的查询,并且很容易以这种方式使您的系统饱和。它只是不擅长为一两个非常大的查询充分利用系统资源,尽管随着为更多类型的查询添加并行查询支持,这种情况正在改善。


如果您使用的是没有并行查询的旧 PostgreSQL,或者您的查询尚未受益于并行查询支持:

你能做的就是把工作分成几块,然后交给工人。你已经提到了这一点:

我可以修改查询以使 postgre 使用所有可用的 CPU 同时并行计算不同行的 GetStatistic 吗?

有多种工具,如DBlinkPL/ProxypgbouncerPgPool-II旨在帮助完成此类工作。或者,您可以自己做,启动(比如说)8 个工作人员,每个工作人员都连接到数据库并UPDATE ... WHERE id BETWEEN ? AND ?使用不重叠的 ID 范围执行语句。一个更复杂的选择是让队列控制器向工作人员分发大约 1000 个 ID 的UPDATE范围,然后该范围要求新的 ID。

请注意,64 个 CPU 并不意味着 64 个并发工作人员是理想的。在写入方面,您的磁盘 I/O 也是一个因素。如果您将UPDATE事务设置为使用 acommit_delay并且(如果对您的业务对此数据的要求安全),您可以减少 I/O 成本,synchronous_commit = 'off'那么同步的负载应该会显着减少。尽管如此,最好的吞吐量很可能远低于 64 个并发工作人员。

GetStatistic通过将函数转换为可内联的 SQL 函数或视图,而不是目前可能是循环繁重的过程 PL/pgSQL 函数,您的函数很可能会变得更快。如果您显示此功能可能会有所帮助。

于 2012-10-17T12:17:30.547 回答