我怎样才能使这个循环更快?
How can I make this loop faster?
我正在为我正在处理的项目使用 Laravel 5.2。关于如何利用 Laravel 使这个循环 运行 更快,有没有人有任何提示?
foreach ($purchaseYears as $purchaseYear){
$totalInventory = \App\Inventory::where('purchase_year', $purchaseYear)->count();
if ($purchaseYear < 1960) { $purchaseYear = 'Pre 1960'; }
else if ($purchaseYear >= 1960 && $purchaseYear < 1965) { $purchaseYear = '1960-64'; }
else if ($purchaseYear >= 1965 && $purchaseYear < 1970) { $purchaseYear = '1965-69'; }
else if ($purchaseYear >= 1970 && $purchaseYear < 1975) { $purchaseYear = '1970-74'; }
else if ($purchaseYear >= 1975 && $purchaseYear < 1980) { $purchaseYear = '1975-79'; }
else if ($purchaseYear >= 1980 && $purchaseYear < 1985) { $purchaseYear = '1980-84'; }
else if ($purchaseYear >= 1985 && $purchaseYear < 1990) { $purchaseYear = '1985-89'; }
else if ($purchaseYear >= 1990 && $purchaseYear < 1995) { $purchaseYear = '1990-94'; }
else if ($purchaseYear >= 1995 && $purchaseYear < 2000) { $purchaseYear = '1995-99'; }
else if ($purchaseYear >= 2000 && $purchaseYear < 2005) { $purchaseYear = '2000-04'; }
else if ($purchaseYear >= 2005 && $purchaseYear < 2010) { $purchaseYear = '2005-09'; }
else if ($purchaseYear >= 2010 && $purchaseYear < 2015) { $purchaseYear = '2010-14'; }
else if ($purchaseYear >= 2015 && $purchaseYear < 2019) { $purchaseYear = '2015-19'; }
if (isset($chartData[$purchaseYear])) {
$prev = $chartData[$purchaseYear];
$chartData[$purchaseYear] = $totalInventory + $prev;
$prev = null;
} else {
$chartData[$purchaseYear] = $totalInventory;
}
}
我认为你可以将日期分解成一个模式,而不是仅仅测试每个十年,像这样:
if ($purchaseYear < 1960) {
$purchaseYear = 'Pre 1960';
} else {
$prefix = substr($purchaseYear,0,2);
$decade = substr($purchaseYear,1,1);
$suffix = substr($purchaseYear,-1);
$purchYear = $prefix . $decade
if ($suffix<5) {
$purchYear .= '0-' . $decade . '4';
} else {
$purchYear .= '5-' . $decade . '9'
}
尚未对此进行测试,但我认为它会满足您的要求。
我认为最耗时的部分应该是执行查询。如果你使用whereIn
,那么我认为你可以只执行一次查询,然后循环遍历结果。我没有测试过,但应该是这样的:
$purchasesByYear = \App\Inventory::select('purchase_year',
DB::raw('count(*) as purchase_count'))
->whereIn('purchase_year', $purchaseYears)
->groupBy('purchase_year')->get();
我认为减少查询执行次数将是让这种情况远离 运行 的主要机会。另外,如果您还没有这样做,我认为向 purchase_year 添加索引应该会有所帮助。
您可以使用一些数学运算来代替大量 elseif 条件来处理年份分组。这实际上可能会稍微慢一些,但是代码的重复性会少一些,而且我相信与您可以对查询部分执行的操作相比,您对这部分所做的任何操作都是微优化。我的建议:
foreach ($purchasesByYear as $purchaseYear) {
$year = $purchaseYear->purchase_year;
if ($year < 1960) {
$yearRange = 'Pre 1960';
} else {
// subtract one until the year is a multiple of five
while ($year % 5) { $year--; }
// then construct the range string using the starting number
$yearRange = $year.'-'.($year+4);
}
if (isset($chartData[$yearRange])) {
$chartData[$yearRange] += $purchaseYear->purchase_count;
} else {
$chartData[$yearRange] = $purchaseYear->purchase_count;
}
}
我正在为我正在处理的项目使用 Laravel 5.2。关于如何利用 Laravel 使这个循环 运行 更快,有没有人有任何提示?
foreach ($purchaseYears as $purchaseYear){
$totalInventory = \App\Inventory::where('purchase_year', $purchaseYear)->count();
if ($purchaseYear < 1960) { $purchaseYear = 'Pre 1960'; }
else if ($purchaseYear >= 1960 && $purchaseYear < 1965) { $purchaseYear = '1960-64'; }
else if ($purchaseYear >= 1965 && $purchaseYear < 1970) { $purchaseYear = '1965-69'; }
else if ($purchaseYear >= 1970 && $purchaseYear < 1975) { $purchaseYear = '1970-74'; }
else if ($purchaseYear >= 1975 && $purchaseYear < 1980) { $purchaseYear = '1975-79'; }
else if ($purchaseYear >= 1980 && $purchaseYear < 1985) { $purchaseYear = '1980-84'; }
else if ($purchaseYear >= 1985 && $purchaseYear < 1990) { $purchaseYear = '1985-89'; }
else if ($purchaseYear >= 1990 && $purchaseYear < 1995) { $purchaseYear = '1990-94'; }
else if ($purchaseYear >= 1995 && $purchaseYear < 2000) { $purchaseYear = '1995-99'; }
else if ($purchaseYear >= 2000 && $purchaseYear < 2005) { $purchaseYear = '2000-04'; }
else if ($purchaseYear >= 2005 && $purchaseYear < 2010) { $purchaseYear = '2005-09'; }
else if ($purchaseYear >= 2010 && $purchaseYear < 2015) { $purchaseYear = '2010-14'; }
else if ($purchaseYear >= 2015 && $purchaseYear < 2019) { $purchaseYear = '2015-19'; }
if (isset($chartData[$purchaseYear])) {
$prev = $chartData[$purchaseYear];
$chartData[$purchaseYear] = $totalInventory + $prev;
$prev = null;
} else {
$chartData[$purchaseYear] = $totalInventory;
}
}
我认为你可以将日期分解成一个模式,而不是仅仅测试每个十年,像这样:
if ($purchaseYear < 1960) {
$purchaseYear = 'Pre 1960';
} else {
$prefix = substr($purchaseYear,0,2);
$decade = substr($purchaseYear,1,1);
$suffix = substr($purchaseYear,-1);
$purchYear = $prefix . $decade
if ($suffix<5) {
$purchYear .= '0-' . $decade . '4';
} else {
$purchYear .= '5-' . $decade . '9'
}
尚未对此进行测试,但我认为它会满足您的要求。
我认为最耗时的部分应该是执行查询。如果你使用whereIn
,那么我认为你可以只执行一次查询,然后循环遍历结果。我没有测试过,但应该是这样的:
$purchasesByYear = \App\Inventory::select('purchase_year',
DB::raw('count(*) as purchase_count'))
->whereIn('purchase_year', $purchaseYears)
->groupBy('purchase_year')->get();
我认为减少查询执行次数将是让这种情况远离 运行 的主要机会。另外,如果您还没有这样做,我认为向 purchase_year 添加索引应该会有所帮助。
您可以使用一些数学运算来代替大量 elseif 条件来处理年份分组。这实际上可能会稍微慢一些,但是代码的重复性会少一些,而且我相信与您可以对查询部分执行的操作相比,您对这部分所做的任何操作都是微优化。我的建议:
foreach ($purchasesByYear as $purchaseYear) {
$year = $purchaseYear->purchase_year;
if ($year < 1960) {
$yearRange = 'Pre 1960';
} else {
// subtract one until the year is a multiple of five
while ($year % 5) { $year--; }
// then construct the range string using the starting number
$yearRange = $year.'-'.($year+4);
}
if (isset($chartData[$yearRange])) {
$chartData[$yearRange] += $purchaseYear->purchase_count;
} else {
$chartData[$yearRange] = $purchaseYear->purchase_count;
}
}