Postgres:如何同时触发多个查询?

时间:2010-08-19 17:25:02

标签: sql postgresql parallel-processing

我有一个更新记录值的过程,我想针对表中的所有记录(超过30k记录)启动它,过程执行时间从2到10秒,因为它取决于网络负载。

现在我在做UPDATE表SET field = procedure_name(paramns);但是有了这么多的记录,处理所有表格需要40分钟。

现在我使用4个不同的连接,使用分叉到背景并触发查询,并将WHERE子句设置为遍历行ID的模数以加快速度,(WHERE id_field%4 =)这样做效果很好并且减少表填充到〜 10分钟。

但我想避免使用cron,shell作业和多个连接,我知道它可以用libpq完成,但有没有办法启动查询(4种不同的非阻塞查询)而不是在单一连接中等到它结束执行?

或者,如果有人可以指出我有关如何编写该函数的一些线索,使用postgres内部,或者只是在C中并将其绑定为存储过程?

干杯大流士

4 个答案:

答案 0 :(得分:1)

我对这个问题有一个肯定的答案 - 如果你愿意与我们分享你的ab锻炼!我一分钟都胖了,我自己也需要答案......

好的,无论如何我都会回答。

如果要在一个数据库服务器上更新一个表,在40分钟内单线程更新,在10分钟内更新4个线程,则瓶颈不是数据库服务器;否则,它会陷入I / O陷入困境。如果你正在执行一堆UPDATES,每条记录一次呼叫,网络往返时间就会让你失望。

我很确定是这种情况,而不是它是数据库的I / O瓶颈或者可能是procedure_name(paramns);需要很长时间。 (如果那是2-10秒的过程,则需要2500分钟才能完成30K记录)。我确信的原因是开始4个并发处理的时间减少了1/4。所以特别是它不是数据库服务器上的i / o问题。

这可能是将业务逻辑放在服务器上的SP中的借口。不幸的是,优化意味着违反规则。结果是难以维护。但是,呃!!

然而,最佳解决方案将设置为使用“批量更新”查询。这可能意味着您必须采取以下几个奇怪且不直观的步骤:

  • 如果多个用户可以同时运行它,则需要进行大量修改。
  • 重构系统,因此procedure_name(paramns)可以通过select语句获取处理所有记录所需的所有数据。可能需要使用创意连接。如果它当然是SP,那么现在你将逻辑移到客户端。
  • 使用程序创建XML或其他可导入的平面文件格式,其中包含要更新的记录的PK以及新的字段值。将所有更新写入此文件,而不是在DB上执行。
  • 在数据库上有一个与此平面文件的布局匹配的临时表
  • 对数据库运行导入 - 清除临时表并导入文件
  • 更新临时表和要更新的表的连接,例如,UPDATE mytbl,mytemp WHERE myPK = mytempPK SET myval = mytempnewval(当然使用正确的连接语法)。
  • 在你打扰编码之前,你可以先“手动”尝试这些东西,看看它是否值得提速。
  • 如果可能的话,你仍然可以将这一切都放在SP中!

我没有做任何保证,特别是当我低头看着我肥胖的肚子时,但是,这有可能将你的更新工作融化到不到一分钟。

答案 1 :(得分:1)

可以一次更新多行。下面是postgres中的一个例子:

UPDATE
    table_name
SET
    column_name = temp.column_name 
FROM
    (VALUES
        (<id1>, <value1>),
        (<id2>, <value2>),
        (<id3>, <value3>)
    ) AS temp("id", "column_name")
WHERE
    table_name.id = temp.id

答案 2 :(得分:0)

PHP具有asynchrone个查询的一些功能:

  • pg_ send_execute()
  • pg_ send_ prepare()
  • pg_send_query()
  • pg_ send_ query_ params()

不了解其他编程语言,你必须深入研究手册。

答案 3 :(得分:0)

我想你不能。单个连接可以立即处理单个查询。它在libpq文档章节“异步命令处理”中有描述:

“成功调用PQsendQuery之后,调用PQgetResult一次或多次以获取结果。在PQgetResult返回空指针之前,不能再次调用PQsendQuery(在同一连接上),表明命令已完成。”