我有一张10米行的大桌子。我需要为每一行获得一些统计值。我有生成此值的函数,例如GetStatistic(uuid)
。这个函数运行速度很慢,结果值不经常更改,所以我在表中创建了列Statistic
,每天执行一次这样的查询:
UPDATE MyTable SET Statistic = GetStatistic(ID);
在选择查询中,我使用列Statistic
而不调用GetStatistic
函数。
问题是,我的生产服务器有64个CPU和大量内存,因此几乎所有数据库都可以缓存到RAM,但是这个查询只使用一个CPU,需要2到3个小时才能执行。
GetStatistic函数使用表,在所有执行UPDATE查询期间都是常量。我可以修改查询以使用所有可用的CPU来获取postgre以同时计算不同行的paralel中的GetStatistic吗?
答案 0 :(得分:10)
PostgreSQL在单个后端执行每个查询,这是一个具有单个线程的进程。它不能使用多个CPU进行查询。它在单个查询中可以实现的I / O并发性也有些限制,实际上只对位图索引扫描执行并发I / O操作,否则依赖操作系统和磁盘系统进行并发I / O.
Pg擅长于许多小型查询的并发加载,并且很容易使系统饱和,它只是在为一两个非常大的查询充分利用系统资源。
您可以做的是将工作分成块并将其交给工人。你曾经提到过:
我可以修改查询以获取postgre来计算paralel中的GetStatistic 对于不同的行,同时使用所有可用的CPU?
有许多工具,例如DBlink,PL/Proxy,pgbouncer和PgPool-II,旨在帮助完成此类工作。或者,您可以自己动手,开始(比如说)每个连接到数据库的8个工作者,并执行具有非重叠ID范围的UPDATE ... WHERE id BETWEEN ? AND ?
语句。一个更复杂的选择是让一个队列控制器向那些UPDATE
范围的工作人员分发大约1000个ID的范围,然后再要求新的。
请注意,64个CPU并不意味着64个并发工作者是理想的。在写入时,您的磁盘I / O也是一个因素。如果您将UPDATE
交易设置为使用commit_delay
并且(如果您的业务要求对此数据安全)synchronous_commit = 'off'
则可以帮助您降低I / O成本应该大大减少。尽管如此,最好的吞吐量可能会远低于64名并发工人。
通过将GetStatistic
函数转换为可内联的SQL函数或视图,而不是大概是一个循环繁重的程序PL / pgSQL函数,很可能会使你的{{1}}函数更快。如果你展示了这个功能,它可能会有所帮助。