IN()条件下的大量占位符会使PDO / Doctrine停止运行

时间:2014-06-04 19:18:46

标签: php mysql pdo doctrine-orm placeholder

设置

我的查询是以大的IN()条件运行的。我不知道为什么我必须这样做,我知道这是一个坏主意,但必须这样做。

因此原始查询看起来像这样:

SELECT * FROM table WHERE col1 IN (1,2,3,4....150000)

问题

主要问题是,当我尝试使用doctrine运行此查询时,它会为每个项目创建一个占位符,大约有150,000个项目。这会给sql带来很大的负担来替换它们,以及PDO由于某种原因在获取它们时。详情如下。

我的主要问题是如何将整个数组用作逗号分隔列表和单个替换。这听起来很容易,但我能想到的每一种方式都不起作用。

到目前为止我做了什么:

我在数组中包含所有这些数字:$ ids

使用doctrine查询构建器:

$qb = createTheQueryBuilder('SELECT * FROM table WHERE col1 IN (:ids)');
$qb->setParameter('ids', $ids, Connection::PARAM_INT_ARRAY);
$results = $qb->execute();
$pairs = $results->fetchAll(PDO::FETCH_KEY_PAIR);

上述方法的问题是它创建了一个?每个价值的占位符。因为$ ids是一个如此庞大的数组,这使得查询和获取速度极慢。我不确定它是否是PDO驱动器中的一个错误,就提取而言,它太慢了 - 它实际上似乎完全停止响应并且php线程一直运行100%运行几个小时$ result->使用fetchall()

我接下来尝试的是:

$qb = createTheQueryBuilder('SELECT * FROM table WHERE col1 IN (:ids)');
$qb->setParameter('ids', implode(',', $ids)); ( <-- changed here )
$results = $qb->execute();
$pairs = $results->fetchAll(PDO::FETCH_KEY_PAIR);

这个问题是它只返回第一个结果。我不确定它是如何或为什么这样做的。

1 个答案:

答案 0 :(得分:1)

正如您所发现的,您无法在一个占位符中插入逗号分隔的字符串。如果可以,那就好。相反,我所知道的唯一选择是将ids直接插入到sql中,而不是使用占位符。

$idStr = implode(',', $ids);

$qb = createTheQueryBuilder("SELECT * FROM table WHERE col1 IN ($idStr)");

显然你应该确保$ ids已被消毒,因为你没有注射保护。

我怀疑它仍然会非常缓慢。 Doctrine和PDO都没有实际处理准备好的语句。它将成为服务器的瓶颈。