-1

我在 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,所以对我来说最重要的是速度。

感谢任何帮助。

4

3 回答 3

1

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

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

您可能想要这样做:

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

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

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

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

于 2013-05-30T15:40:12.473 回答
0

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

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

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

我认为 array_merge 和通过 PDOStatement 循环的“丑陋”都减慢了我的脚本。

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

于 2013-05-30T17:28:32.640 回答
0

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

有时让一个函数进行一步插入是很好的,因为当函数返回时,函数中使用的所有内存都将被释放,因此您的内存使用率保持在较低水平。

于 2013-06-04T08:24:23.373 回答