【问题标题】:Query from PHP to PostgreSQL is very slow, how to increase?从PHP到PostgreSQL查询很慢,怎么增加?
【发布时间】:2019-07-22 04:01:42
【问题描述】:

PHP:

$dbconn = pg_connect("host=127.0.0.1 dbname=test user=test password=test");
$start = microtime(true); 
for($i=1;$i<=5000;$i++) { 
    pg_query("insert into testtb(uid,sid) values($i,$i)"); 
} 
echo ( (microtime(true) - $start) *1000).' ms';
// result: 15504.348993301 ms

PSQL 外壳:

begin for r in 1..5000 loop 
insert into testtb (uid,sid) values(r,r); 
end loop; end; $$; 
// result: 43 ms

testtb 很简单,只有两列 siduid,都被索引了。 PHP 和 PG 在同一台服务器上。 从测试中我们可以看到,对于 5000 条记录的插入,Postgres 的速度非常快。但是当使用 PHP 时,速度显着下降。那么我们怎样才能提高 PHP+PG 的速度呢?

编辑:请注意结果:PHP - 15504 ms, psql shell - 43 ms

【问题讨论】:

  • 为什么要执行 5000 个单独的插入而不是 5000 个值元组的插入?是否设置了任何索引?您是否排除了网络问题?
  • 如果您正在填充数据库,您是否尝试使用 COPY?它针对加载大量行进行了优化。
  • @NicoHaase 用于测试并与 shell 进行比较。
  • @abestrad 不,这不是真实情况,而是测试。请注意,从 psql shell 插入非常快,所以问题不应该来自 db 本身。
  • 是新表吗?您是否尝试在插入所有行后创建索引?在现有数据上创建索引比在插入每一行时更新它更快。

标签: php postgresql


【解决方案1】:

看起来像一个灾难性的往返延迟问题。我敢打赌,您的 PHP 脚本运行在单独的计算机上(不是 127.0.0.1)?我确实想知道,相比之下,它的表现如何?

 $db = new PDO('pgsql:host=localhost;port=5432;dbname=test;', 'username', 'password', array(PDO::ATTR_EMULATE_PREPARES => false, PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION));
$start = microtime(true); 
$db->beginTransaction();
$stm=$db->prepare("INSERT INTO testtb(uid,sid) VALUES(?,?)");
for($i=1;$i<=5000;++$i) { 
    $stm->execute(array($i,$i));
} 
$db->commit();
echo ( (microtime(true) - $start) *1000).' ms';

编辑:如果它们确实在同一台计算机上运行,​​我的下一个猜测是您的 PHP 脚本通过 TCP 连接,而 PSQL shell 通过 unix 套接字连接。 unix 套接字比 TCP 连接快得多,即使在 localhost 上也是如此,但我不希望有如此巨大的差异 - 除非你有一个防火墙可以拦截 localhost 到 localhost 的连接,有问题的防火墙可能导致严重的延迟问题,这可以解释这一点。尝试使用 PHP 连接到 unix 套接字,例如

 $db = new PDO('pgsql:unix_socket=/var/run/postgresql.sock;dbname=test;', 'username', 'password', array(PDO::ATTR_EMULATE_PREPARES => false, PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION));
$start = microtime(true); 
$db->beginTransaction();
$stm=$db->prepare("INSERT INTO testtb(uid,sid) VALUES(?,?)");
for($i=1;$i<=5000;++$i) { 
    $stm->execute(array($i,$i));
} 
$db->commit();
echo ( (microtime(true) - $start) *1000).' ms';

它的表现如何? (应该比 TCP 连接更好,但如果你有防火墙问题,它可以比 TCP 连接执行 MUCH

如果你不知道你的 pqsql unix socket 在哪里,这个命令通常会找到它:sudo find / -iname "*.sock*" 2 &gt;/dev/null

(顺便说一句,我认为/var/run/postgresql.sock 是 Debian 和 Ubuntu 系统上的默认位置)

【讨论】:

  • "PHP和PG在同一个服务器"
  • @Elect2 很奇怪。我的下一个猜测是 PHP 通过 TCP 连接,而 PSQL shell 通过 unix 套接字连接(即使在 localhost 上,unix 套接字也比 TCP 连接快得多),但我不希望有如此巨大的差异(除非防火墙在TCP连接的方式?甚至拦截本地主机到本地主机连接的防火墙?它们确实存在)
  • @Elect2 我添加了有关 tcp-socket 与 unix-socket 理论的信息,请重新阅读我的帖子
  • 应该不是防火墙问题。我已经在我自己的 virtualbox 和 aws ec2 上进行了测试,结果是一样的。 (ubuntu 16.04,nginx,php7-fpm,pg10)。顺便说一句:测试了 $db->commit 方法,它更快(300 毫秒),但我知道它会更快,因为它一次发送所有查询。我期望的是如何通过查询速度增加查询。我还通过查询 5000 插入测试了 PHP+Mongodb 查询,结果为 150 毫秒。
  • @Elect2 hmm.. 好吧,用 unix 套接字测试速度,然后告诉我速度有多快
【解决方案2】:

最后我发现这个结果是正常。 使用 PHP 时,每个查询插入 1 行。我在我的 PostgreSQL 服务器上运行 TPS 基准测试,结果约为 500 TPS。所以花 15 秒插入 5000 行是合理的。

至于PostgreSQL的shell为什么很快,我觉得不是循环查询,而是单个批量查询。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-06-24
    • 1970-01-01
    • 2022-12-13
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多