合并两个具有相同键的 Laravel 集合进行聚合存在性能问题

问题描述 投票:0回答:1

我目前正在开发一个 Laravel 应用程序,该应用程序合并来自两个集合的统计信息:postStats(标准集合)和 contentStats(LazyCollection)。我使用的 mergeStats 方法多次迭代每个集合以求和各种指标,这在处理大型数据集时会导致性能问题,对于 1000 个帖子和 1000 个内容,需要大约 10 秒,记录可能比这个大得多.

代码:

private function mergeStats(Collection $postStats, LazyCollection $contentStats, bool $dashboardStats = false): array
{
    $startTime = microtime(true);
    $keys = [
        'reactions_count',
        'comments_count',
        'sc_shares_count',
        'confirmed_regular_shares_count',
        'sc_clicks_count',
        'unconfirmed_regular_shares_count',
        'confirmed_shares_click_count',
    ];

    // Current logic here to merge postStats and contentStats, 
    $mergedStats = $postStats->concat($contentStats)->reduce(static function ($carry, $stats) use ($keys) {
        foreach ($keys as $key) {
            $carry[$key] = ($carry[$key] ?? 0) + ($stats[$key] ?? 0);
        }
        return $carry;
    }, array_fill_keys($keys, 0));

    $mergedStats['dashboard_stats'] = $dashboardStats;

    return CalculateEngagementMetricsAction::run($mergedStats); //based on the merged stats, it does some calculations, This action is not the culprit for performance. 
}
php mysql laravel eloquent
1个回答
0
投票

为了提高 mergeStats 方法的性能,关键是优化迭代集合和汇总指标的方式。由于您同时使用标准集合和 LazyCollection,因此我们可以利用惰性求值来更有效地处理大型数据集。

解决方案

  1. Convert postStats to a LazyCollection:这确保两个集合都被延迟处理,避免一次将所有记录加载到内存中的开销。
  2. 延迟连接和减少:使用 LazyCollection 将允许您有效地迭代两个集合,而无需将它们全部强制放入内存中,从而提高处理大型数据集时的性能。

以下是调整 mergeStats 方法的方法:

use Illuminate\Support\LazyCollection;

private function mergeStats(Collection $postStats, LazyCollection $contentStats, bool $dashboardStats = false): array
{
    $keys = [
        'reactions_count',
        'comments_count',
        'sc_shares_count',
        'confirmed_regular_shares_count',
        'sc_clicks_count',
        'unconfirmed_regular_shares_count',
        'confirmed_shares_click_count',
    ];

    // Convert postStats to LazyCollection for efficient handling
    $postStats = LazyCollection::make(function () use ($postStats) {
        foreach ($postStats as $item) {
            yield $item;
        }
    });

    // Concatenate and reduce both collections lazily
    $mergedStats = $postStats->concat($contentStats)->reduce(static function ($carry, $stats) use ($keys) {
        foreach ($keys as $key) {
            $carry[$key] = ($carry[$key] ?? 0) + ($stats[$key] ?? 0);
        }
        return $carry;
    }, array_fill_keys($keys, 0));

    $mergedStats['dashboard_stats'] = $dashboardStats;

    return CalculateEngagementMetricsAction::run($mergedStats);
}

说明:

  • LazyCollection:延迟处理两个集合可减少内存使用并加快处理速度,尤其是对于大型数据集。
  • concat+reduce:集合在一次传递中连接和处理,最大限度地减少所需的迭代次数。

这种方法应该可以显着提高性能,特别是对于大型数据集。如果您需要进一步说明或帮助,请告诉我!

© www.soinside.com 2019 - 2024. All rights reserved.