使用whereIn查询65k +条记录

时间:2019-11-26 15:58:07

标签: mysql laravel laravel-query-builder

我具有导出功能,我想使用给定的ID查询和导出。我找到了一种使用skip()take()进行查询的解决方案,但是现在whereIn('id', $ids)给我错误,因为到目前为止它有85,000条记录。

  

PDOException:SQLSTATE [HY000]:常规错误:1390准备好的语句包含太多占位符

我使用的解决方案是:

public function handle() {
    $max = 5000;
    $total = $this->givenIds->count();

    $pages = ceil($total / $max);

    for ($i = 1; $i < ($pages + 1); $i++) {
        $offset = (($i - 1) * $max);
        $start = ($offset == 0 ? 0 : ($offset + 1));

        MyModel::whereIn('id', $givenIds)
                 ->orderBy('created_at', 'desc')
                 ->skip($start)
                 ->take($max)
                 ->get();

       // $this->generateTempCsv();
    }

    // $this->combineTempCSVs()
}

在没有瓶颈的情况下,它运行良好,直到出现过多的占位符错误为止。现在,我收到此错误,我尝试:

$query = MyModel::orderBy('created_at', 'desc')

foreach ($this->givenIds->chunk(2000) as $i => $chunk) {
    if ($i == 0) {
       $query = $query->whereIn('id', $chunk);
    } else {
       $query = $query->orWhereIn('id', $chunk);
    }
}

这给出了相同的错误。

如果我想使用给定的ID进行查询,并且仍然想保留“ orderBy-created_at”而不会出现瓶颈,该怎么办?

givenIds来自控制器(上面的代码是Job):

$givenIds = MyModel::select('id', 'created_at')
                    ->where(function($q) use ($dateRange, $queries) {
                            $this->applyQueryFilters($q, $queries, $dateRange);
                     })
                     ->orderBy('created_at', 'desc')
                     ->pluck('id');

Exporter::dispatch($givenIds)->onQueue('export');

PS:之所以使用$givenIds是因为有过滤器,首先在应用过滤器后将$givenIds传递到工作中,然后获得了相关的ID。在获取$givenIds并从那里开始排序时,我是否需要按ID排序?

1 个答案:

答案 0 :(得分:1)

尝试以下操作:在数据库配置文件中的sql下或用于连接数据库的驱动程序中,添加如下字段options

'options'=> [PDO::ATTR_EMULATE_PREPARES => true]

PHP API实际上(check this):

  

某些驱动程序不支持本机预处理语句或对此的支持有限。

另一种解决方案应该是更改驱动程序,但我想在database.php中添加一行更容易

可能的副作用报告::这可能会将返回值强制转换为字符串,如果您使用===作为比较运算符,则会影响您的代码。您可以使用模型中的protected $casts变量解决此问题(如果您使用的是Laravel)