*/ private array $queries = []; public function __construct() { DB::listen(function (QueryExecuted $event) { if (! $this->collecting) { return; } $this->queries[] = ['sql' => $event->sql, 'time' => (float) $event->time]; }); } /** * 콜백 실행 구간의 쿼리를 수집합니다. * * @template TReturn * * @param \Closure(): TReturn $callback 계측 대상 작업 * @return array{value: TReturn, queries: array} 반환값과 수집 결과 */ public function collect(\Closure $callback): array { $this->queries = []; $this->collecting = true; try { $value = $callback(); } finally { $this->collecting = false; } return ['value' => $value, 'queries' => $this->queries]; } /** * 수집된 쿼리를 요약합니다. * * @param array $queries 수집 결과 * @return array{count: int, db_ms: float, n_plus_one: array} 요약 */ public function summarize(array $queries): array { $grouped = []; foreach ($queries as $query) { $grouped[$query['sql']] = ($grouped[$query['sql']] ?? 0) + 1; } arsort($grouped); $candidates = []; foreach ($grouped as $sql => $count) { if ($count < self::N_PLUS_ONE_THRESHOLD) { continue; } $candidates[] = ['count' => $count, 'sql' => $sql]; } return [ 'count' => count($queries), 'db_ms' => round(array_sum(array_column($queries, 'time')), 2), 'n_plus_one' => $candidates, ]; } }