绩效考核
虽然接受的答案可能会解决 OP 问题,但这 不是 OPTIMAL SOLUTION数据库性能。
因为当whereYear() 或whereMonth() 帮助器应用于查询记录时,它会进行查询Non-SARGable。这意味着如果比较列 created_at 在数据库中被索引,则在搜索数据时会忽略此索引。见What makes a SQL statement sargable?
考虑以下表达式
$posts = Mjblog::whereYear('created_at', '=', $year)
->whereMonth('created_at', '=', $month)
->get();
查询结果会是这样的
select *
from mjblog
where year(`created_at`) = :year
and month(`created_at`) = :month
可以清楚地看到上述查询是不可分割的,因为year() 和month() 函数应用于created_at,这会产生非索引值。
要使其成为 SARGable 表达式,最好在比较索引列时定义值的确切/范围。与 OP 一样,范围可以从月份和年份值导出为
$year = 2000;
$month = 2;
$date = \Carbon\Carbon::parse($year."-".$month."-01"); // universal truth month's first day is 1
$start = $date->startOfMonth()->format('Y-m-d H:i:s'); // 2000-02-01 00:00:00
$end = $date->endOfMonth()->format('Y-m-d H:i:s'); // 2000-02-29 23:59:59
现在SARGable表达式可以写成
select *
from mjblog
where created_at between :start and :end
或者
select *
from mjblog
where created_at >= :start
and created_at <= :end
在查询构建器中可以表示为
$posts = Mjblog::whereBetween('created_at', [$start, $end])
->get();
或者
$posts = Mjblog::where('created_at', '>=', $start)
->where('created_at', '<=', $end)
->get();
另一篇有用的文章强调了Non-SARGable Predicates & Anti-Patterns 的缺点