Laravel$query->;toSql()将丢失额外的关系


Laravel $query->toSql() loses relation extras

我有下面的函数,它试图匹配特定白名单字段上的用户,对于少量数据,它非常有效,但在我们的生产环境中,我们可能有超过100万的用户记录,Eloquent在最后创建模型时(可以理解)很慢:$query->get()。今天早上,我问了一个关于如何加快速度的问题,得到的答案很好,很有效,现在唯一的问题是,发送到DB::select($query->toSql()...的查询丢失了我需要的所有额外关系信息。那么,有没有办法(尽可能多地保留当前函数)向DB::select添加联接,这样我就可以保持速度而不会丢失关系,或者需要完全重写?

recipients查询应该包括标签、联系人详细信息、联系人首选项等的关系,但$query->toSql()生成的sql没有联接,只引用一个表。

public function runForResultSet()
{
    $params = [];
    // Need to ensure that when criteria is empty - we don't run
    if (count($this->segmentCriteria) <= 0) {
        return;
    }
    $query = Recipient::with('recipientTags', 'contactDetails', 'contactPreferences', 'recipientTags.tagGroups');
    foreach ($this->segmentCriteria as $criteria) {
        $parts = explode('.', $criteria['field']);
        $fieldObject = SegmentTableWhiteListFields::where('field', '=', $parts[1])->get();
        foreach ($fieldObject as $whiteList) {
            $params[0] = [$criteria->value];
            $dateArgs = ((strtoupper($parts[1]) == "AGE" ? false : DatabaseHelper::processValue($criteria)));
            if ($dateArgs != false) {
                $query->whereRaw(
                    DatabaseHelper::generateOperationAsString(
                        $parts[1],
                        $criteria,
                        true
                    ),
                    [$dateArgs['prepared_date']]
                );
            } else {
                // Need to check for empty value as laravel's whereRaw will not run if the provided
                // params are null/empty - In which case we need to use whereRaw without params.
                if (!empty($criteria->value)) {
                    $query->whereRaw(
                        'DatabaseHelper::generateOperationAsString(
                            $parts[1],
                            $criteria
                        ),
                        $params[0]
                    );
                } else {
                    $query->whereRaw(
                        'DatabaseHelper::generateOperationAsString(
                            $parts[1],
                            $criteria
                        )
                    );
                }
            }
        }
    }
    // Include any tag criteria
    foreach ($this->segmentRecipientTagGroupCriteria as $criteria) {
        $startTagLoopTime = microtime(true);
        switch (strtoupper($criteria->operator)) {
            // IF NULL check for no matching tags based on the tag group
            case "IS NULL":
                $query->whereHas(
                    'recipientTags',
                    function ($subQuery) use ($criteria) {
                        $subQuery->where('recipient_tag_group_id', $criteria->recipient_tag_group_id);
                    },
                    '=',
                    0
                );
                break;
            // IF NOT NULL check for at least 1 matching tag based on the tag group
            case "IS NOT NULL":
                $query->whereHas(
                    'recipientTags',
                    function ($subQuery) use ($criteria) {
                        $subQuery->where('recipient_tag_group_id', $criteria->recipient_tag_group_id);
                    },
                    '>=',
                    1
                );
                break;
            default:
                $query->whereHas(
                    'recipientTags',
                    function ($subQuery) use ($criteria) {
                        $dateArgs = (DatabaseHelper::processValue($criteria));
                        $subQuery->where('recipient_tag_group_id', $criteria->recipient_tag_group_id);
                        if ($dateArgs != false) {
                            $subQuery->whereRaw(
                                DatabaseHelper::generateOperationAsString(
                                    'name',
                                    $criteria,
                                    true
                                ),
                                [$dateArgs['prepared_date']]
                            );
                        } else {
                            // Need to check for empty value as laravel's whereRaw will not run if the provided
                            // params are null/empty - In which case we need to use whereRaw without params.
                            if (!empty($criteria->value)) {
                                $subQuery->whereRaw(
                                    'DatabaseHelper::generateOperationAsString(
                                        'name',
                                        $criteria
                                    ),
                                    [$criteria->value]
                                );
                            } else {
                                $subQuery->whereRaw(
                                    'DatabaseHelper::generateOperationAsString(
                                        'name',
                                        $criteria
                                    )
                                );
                            }
                        }
                    },
                    '>=',
                    1
                );
        }
    }
    //$collection = $query->get(); // slow when dealing with > 25k rows
    $collection = DB::select($query->toSql(), $query->getBindings()); // fast but loses joins / relations
    // return the response
    return 'ApiResponse::respond($collection);
}

所谓关系信息丢失,是指关系急切地加载了您通过()传递给的名称吗?

此信息没有丢失,因为它从未出现在查询中。当您加载这样的关系时,Eloquent会运行单独的SQL查询,以从主结果集中获取对象的相关对象。

如果希望这些关系中的列出现在结果集中,则需要显式地将联接添加到查询中。您可以在文档中找到有关如何执行此操作的信息:https://laravel.com/docs/5.1/queries#joins