我有以下功能,它尝试匹配特定白名单字段上的用户,这些字段对于少量数据非常有效,但在我们的生产环境中,我们可以使用> 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);
}
答案 0 :(得分:1)
丢失的关系信息是否意味着关系急切地将您传递给的名称加载到()?
此信息未丢失,因为它从未出现在查询中。当您加载这样的关系时,Eloquent会运行单独的SQL查询来从主结果集中获取对象的相关对象。
如果希望这些关系中的列位于结果集中,则需要明确地向查询添加联接。您可以在文档中找到有关如何执行此操作的信息:https://laravel.com/docs/5.1/queries#joins