【问题标题】:PDO PHP Postgres: slow fetching of dataPDO PHP Postgres:缓慢获取数据
【发布时间】:2013-05-30 14:28:52
【问题描述】:

我在 PostgreSQL 9.2.4 上使用 PDO 并试图从具有数百万行的表中获取数据。我的查询返回大约 100.000 行。 我不使用任何 PDOStatements 的 fetch 函数,我只是使用 PDO Objecte itels 的结果并循环遍历它。 但随着时间的推移,它变得越来越慢。一开始它每秒获取 200 行。但越接近尾声,它就越慢。现在在第 30.000 行,它每秒只获取 1 行。为什么越来越慢。

我这样做,很简单:

$dbh = new PDO("pgsql...");
$sql = "SELECT x, y FROM point WHERE name is NOT NULL and place IN ('area1', 'area2')";
$res = $dbh->query($sql);
$ins_sql = "INSERT INTO mypoints (x, y) VALUES ";
$ins_vals = [];
$ins_placeholders = [];
foreach($res as $row) {
  $ins_placeholders[] = "(?,?)"; 
  $ins_vals = array_merge($ins_vals, [$row['x'], $row['y']]);
  printCounter();
}

// now build up one insert query using placeholders and values, 
// to insert all of them in one shot into table mypoints

函数 printCounter 只是增加一个 int var 并打印它。因此,在我从中创建插入语句之前,我可以看到它已经在该数组中放入了多少行。我使用一次性插入来加快速度,比进行 100.000 次插入要好。 但是那个 foreach 循环随着时间的推移变得越来越慢。我怎样才能提高速度。 fetch()和foreach中使用pdostatement的简单循环方法有区别吗?

当我启动这个 php 脚本时,查询大约需要 5-10 秒。所以这与表的设置方式以及我是否需要索引无关。 我有其他表返回 100 万行,我不确定获取它们的最佳方法是什么。如果需要,我可以提高 PHP 的 memory_limit,所以对我来说最重要的是速度。

感谢任何帮助。

【问题讨论】:

  • 如果速度是您主要关心的问题,请不要使用 PDO,而是使用本机库。它至少快 10%。
  • 好吧,我使用 PDO,因为在 fetch 之后我确实插入了它们并希望使用 PDO 的自动引用功能
  • “引用”是指转义?
  • 是的,我的意思是绑定到 ? pdostatement 的执行调用上的字符。否则我需要使用 addlashes 或类似的东西。 PDO 真的比原生的慢吗?
  • 是的,如果您仍想执行数千次插入,我建议您使用准备好的查询。这样,您的值将自动转义,并且数据库不会每次都重新评估查询计划。

标签: php postgresql pdo fetch


【解决方案1】:

缓慢不太可能与数据库有关,因为在$dbh->query() 调用之后,查询完成并且结果行都在内存中(它们还没有在PHP变量中,但它们在内存中可在 pgsql 模块级别访问)。

更有可能的罪魁祸首是array_merge 操作。数组在每次循环迭代时都会变大,并且每次操作都会重新创建整个数组。

您可能想要这样做:

$ins_vals[] = [$row['x'], $row['y']];

虽然就个人而言,当涉及速度时,我会使用更简单的扁平结构:

$ins_vals[] = $x;
$ins_vals[] = $y;

另一个不相关的点是它似乎构建了一个包含大量占位符的查询,这不是占位符通常使用的方式。要将大量值发送到服务器,有效的方法是使用COPY,如果不是普通插入,可能会使用到临时表,然后进行服务器端合并操作。

【讨论】:

    【解决方案2】:

    我不知道为什么,而是使用 fetch() 方法并像这样进行 $ins_val 填充:

    $ins_vals[] = $x;
    $ins_vals[] = $y;
    

    现在使用 beginTransaction 和 commit 使我的脚本快得难以置信。 现在只需大约 1 分钟即可添加我的 100.000 分。

    我认为 array_merge 和遍历 PDOStatement 的“丑陋”循环都会减慢我的脚本速度。

    为什么有人对我的问题投了反对票?你是因为我缺乏知识而惩罚我吗?谢谢。

    【讨论】:

      【解决方案3】:

      好的,我生成了一个类,我在其中设置 sql,然后通过方法调用为每一行放置值。每当达到特定限制时,它就会启动一个事务,使用与我放置的值一样多的占位符准备语句,然后使用具有所有值的数组执行它,然后提交。 这似乎足够快,至少它不再变慢了。 出于某种原因,正如 Daniel 所建议的那样,在平面结构中添加值会更快。这对我来说已经足够了。

      有时候让一个函数做一步插入是好的,因为当函数返回时,函数使用的所有内存都会被释放,所以你的内存使用率很低。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2012-04-21
        • 2017-07-22
        • 2021-01-18
        • 2023-02-16
        • 1970-01-01
        • 2012-10-12
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多