웹사이트 속도가 느린가요? 로딩하는데 시간이 오래 걸리나요? 사용자들이 거의 사용할 수 없다고 불평하고 있나요? 데이터베이스 쿼리를 확인해야 합니다. 모든 데이터베이스 쿼리를 쉽게 분석할 수 있는 깔끔한 방법을 보여 드리겠습니다.
물론 웹 사이트가 느린 데에는 여러 가지 이유가 있지만 가장 일반적인 이유 중 하나는 느린 데이터베이스 쿼리입니다.
그러나 laravel에서는 (대부분의 경우) 데이터베이스에서 데이터를 가져오기 위해 SQL을 사용하지 않고 Eloquent ORM 및 Query Builder를 사용합니다. 이로 인해 때때로 사이트 오류를 일으키는 쿼리를 정확히 찾아내기가 어렵습니다. 너무 천천히 하세요.
다행히도 laravel에서는 쿼리가 실행될 때마다 호출되는 콜백을 정의할 수 있습니다(여기 참조). 이렇게 하려면 서비스 제공자(예: AppServiceProvider)에 다음 코드를 추가하세요.
public function boot() { DB::listen(function ($query) { // TODO: make this useful }); }
보시다시피 QueryExecuted$query
,这个变量是 QueryExecuted 类的一个实例。这意味着我们可以访问有关已执行查询的一些信息:
DB::listen(function ($query) { $query->sql; // 执行的 sql 字符串 $query->bindings; // 传递给sql查询的参数(这将替换sql字符串中的 "?") $query->time; // 执行查询所用的时间; });
这是非常有用的信息,现在我们可以通过查看 $query->time
属性来识别慢查询。 但这并没有告诉我们在我们的代码中查询执行的位置。
即使该 $query
变量没有给我们任何关于其来源的信息, 我们仍然可以使用 PHP 内置函数 debug_backtrace()
获取该信息。
DB::listen(function ($query) { dd(debug_backtrace()); });
如果你在你的项目上运行它,你会在浏览器上看到类似这样的东西:
array:63 [▼ 0 => array:7 [▼ "file"=>"/home/cosme/Documents/projects/cosme.dev/vendor/laravel/framework/src/Illuminate/Events/Dispatcher.php" "line" => 404 "function" => "App\Providers\{closure}" "class" => "App\Providers\AppServiceProvider" "object" => App\Providers\AppServiceProvider {#140 ▶} "type" => "->" "args" => array:1 [▶] ] 1 => array:7 [▼ "file" => "/home/cosme/Documents/projects/cosme.dev/vendor/laravel/framework/src/Illuminate/Events/Dispatcher.php" "line" => 249 "function" => "Illuminate\Events\{closure}" "class" => "Illuminate\Events\Dispatcher" "object" => Illuminate\Events\Dispatcher {#27 ▶} "type" => "->" "args" => array:2 [▶] ] 2 => array:7 [▼ "file" => "/home/cosme/Documents/projects/cosme.dev/vendor/laravel/framework/src/Illuminate/Database/Connection.php" "line" => 887 "function" => "dispatch" "class" => "Illuminate\Events\Dispatcher" "object" => Illuminate\Events\Dispatcher {#27 ▶} "type" => "->" "args" => array:1 [▶] ] ....
这是一个数组,其中包含请求中到目前为止的每个函数调用。我将只关注每个数组中的 file
和 line
键。
如果你仔细看,你会发现在我的例子中有 63 个函数调用,这是一个简单的应用程序,如果在更复杂的应用程序中,可能会更多。更糟糕的是,如果您查看顶部的那些, 它们都是 laravel 框架的内部函数。我们是否应该逐一查看,直到找到可能对我们有帮助的东西?
正如我之前所说,它们中的大多数是内部框架调用,这意味着这些文件中的大多数都在我们的 vendor/
目录中。这意味着我们可以检查每个 file
并过滤掉任何具有 vendor/
的调用,如下所示:
DB::listen(function ($query) { $stackTrace = collect(debug_backtrace())->filter(function ($trace) { return !str_contains($trace['file'], 'vendor/'); }); dd($stackTrace); });
在这里,我将数组转换为集合以使用该 filter
方法,如果 file
当前 $trace
有 vendor/
클래스의 인스턴스입니다. 이는 실행된 쿼리에 대한 일부 정보에 액세스할 수 있음을 의미합니다.
Illuminate\Support\Collection {#1237 ▼ #items: array:5 [▼ 12 => array:7 [▼ "file" => "/home/cosme/Documents/projects/cosme.dev/app/Models/Post.php" "line" => 61 "function" => "get" "class" => "Illuminate\Database\Eloquent\Builder" "object" => Illuminate\Database\Eloquent\Builder {#310 ▶} "type" => "->" "args" => [] ] 16 => array:6 [▶] 17 => array:6 [▶] 61 => array:7 [▶] 62 => array:4 [▶] ] #escapeWhenCastingToString: false }
이는 매우 유용한 정보입니다. 이제 $query->time
속성을 보고 느린 쿼리를 식별할 수 있습니다.
.
$query
변수가 원본에 대한 정보를 제공하지 않더라도 PHP 내장 함수 debug_backtrace()
를 사용하여 해당 정보를 얻을 수 있습니다. .
public function boot() { DB::listen(function ($query) { $location = collect(debug_backtrace())->filter(function ($trace) { return !str_contains($trace['file'], 'vendor/'); })->first(); // grab the first element of non vendor/ calls $bindings = implode(", ", $query->bindings); // format the bindings as string Log::info(" ------------ Sql: $query->sql Bindings: $bindings Time: $query->time File: ${location['file']} Line: ${location['line']} ------------ "); }); }
프로젝트에서 이것을 실행하면 브라우저에 다음과 같은 내용이 표시됩니다.
[2022-02-03 02:20:14] local.INFO: ------------ Sql: select "title", "slug", "body" from "posts" where "published" = ? order by "id" desc Bindings: 1 Time: 0.18 File: /home/cosme/Documents/projects/cosme.dev/app/Models/Post.php Line: 61 ----------
이것은 요청에서 지금까지 모든 함수 호출을 포함하는 배열입니다. 각 배열의 file
및 line
키에만 집중하겠습니다.
앞서 말했듯이 대부분은 내부 프레임워크 호출이므로 이러한 파일의 대부분은 vendor/
디렉토리 중간에 있습니다. 즉, 각 파일
을 확인하고 다음과 같이 vendor/
를 사용한 호출을 필터링할 수 있습니다.
여기서 배열을 컬렉션으로 변환합니다. 필터 사용
메서드, 현재 $trace
에 vendor/
가 있는 파일
이 있으면 컬렉션에서 해당 파일을 제거합니다. 위의 코드를 실행하면 다음과 같은 내용이 표시됩니다.
항목이 훨씬 적습니다. 63개에서 5개로 줄었습니다. 가장 좋은 점은 컬렉션의 첫 번째 항목이 SQL 쿼리를 트리거하는 정확한 위치라는 것입니다. 이는 이 정보를 추출하여 가장 느린 쿼리를 찾을 수 있음을 의미합니다.
로그로 인쇄이제 필요한 모든 정보를 얻었으니 가장 느린 쿼리를 검사하고 찾을 수 있도록 기록해 보는 것은 어떨까요? :
rrreee🎜애플리케이션에서 이것을 사용하는 경우 로그 파일을 확인할 수 있으며 다음과 같은 쿼리 정보가 표시됩니다.🎜rrreee🎜이제 어떤 쿼리가 가장 느린지 알고 하나씩 처리하기 시작합니다. 더 빠르거나 적어도 캐시합니다. 🎜🎜🎜🎜🎜확장 디버깅🎜🎜🎜이것은 디버깅에 적합하지만 이 기술은 다양한 방법으로 사용될 수 있습니다. 🎜🎜🎜 이번 주 가장 느린 쿼리를 보여주는 주간 보고서를 만들 수 있습니다. 🎜🎜🎜🎜쿼리가 시간 임계값을 초과하면 Slack 알림을 받을 수 있습니다. 🎜🎜🎜🎜 귀하와 팀이 실행된 모든 쿼리를 볼 수 있는 대시보드를 만들 수 있습니다. 🎜🎜🎜무한합니다. 🎜🎜【관련 추천: 🎜laravel 동영상 튜토리얼🎜】🎜위 내용은 Laravel에서 가장 느린 쿼리를 찾는 방법에 대한 간략한 분석의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!