使用 whereIn 查询 65k+ 条记录

Querying 65k+ records with whereIn

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

PDOException: SQLSTATE[HY000]: General error: 1390 Prepared statement contains too many placeholders

我使用的解决方案是:

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);
    }
}

这给出了同样的错误。

如果我想使用 givenIds 查询,并且仍然想保持 "orderBy - created_at" 没有瓶颈我应该怎么做?

givenIds来自Controller(如上代码为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的原因是因为有过滤器,首先我在应用过滤器后得到相关的id,然后将$givenIds传递到作业中。获取 $givenIds 时是否需要按 id 排序并取决于那里的顺序?

试试这个:在您的数据库配置文件中,在 sql 或您用来连接到数据库的驱动程序下,添加一个字段 options 像这样

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

PHP API 事实上说 (check this):

Some drivers do not support native prepared statements or have limited support for them.

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

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