Laravel $ query-> toSql()会失去关系附加功能

时间:2016-01-08 12:12:24

标签: php laravel laravel-5 eloquent

我有以下功能,它尝试匹配特定白名单字段上的用户,这些字段对于少量数据非常有效,但在我们的生产环境中,我们可以使用> 100万用户记录,Eloquent在($query->get()最后创建模型时(可理解)很慢。我问了一个问题morning关于如何加快这个问题,并且接受的答案非常精彩并且有效,现在唯一的问题是发送给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);
}

1 个答案:

答案 0 :(得分:1)

丢失的关系信息是否意味着关系急切地将您传递给的名称加载到()

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

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