Ist Ihre Website langsam? Dauert das Laden lange? Beschweren sich Benutzer darüber, dass es fast unbrauchbar ist? Sie sollten Ihre Datenbankabfragen überprüfen. Ich zeige Ihnen eine praktische Möglichkeit, alle Ihre Datenbankabfragen einfach zu analysieren.
Natürlich gibt es viele Gründe, warum Ihre Website langsam sein kann, aber einer der häufigsten Gründe sind langsame Datenbankabfragen.
Aber in Laravel verwenden wir (meistens) kein SQL, um Daten aus der Datenbank abzurufen, sondern Eloquent ORM und Query Builder, was es manchmal schwierig macht, die Abfrage zu lokalisieren, die unsere Website verursacht Sei so langsam.
Glücklicherweise können wir in Laravel einen Rückruf definieren, der jedes Mal aufgerufen wird, wenn eine Abfrage ausgeführt wird (siehe hier). Fügen Sie dazu den folgenden Code zu einem beliebigen Dienstanbieter (z. B. AppServiceProvider) hinzu:
public function boot() { DB::listen(function ($query) { // TODO: make this useful }); }
Wie Sie sehen können, erhalten wir eine Variable $query
, die Eine Instanz der 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/
-Klasse. Dies bedeutet, dass wir Zugriff auf einige Informationen über die ausgeführte Abfrage haben:
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 }
Das sind sehr nützliche Informationen. Jetzt können wir langsame Abfragen identifizieren, indem wir uns das Attribut $query->time
ansehen.
.
Auch wenn uns die Variable $query
keine Informationen über ihren Ursprung liefert, können wir diese Informationen dennoch mithilfe der in PHP integrierten Funktion debug_backtrace()
abrufen .
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']} ------------ "); }); }
Wenn Sie dies in Ihrem Projekt ausführen, sehen Sie im Browser etwa Folgendes:
[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 ----------
Dies ist ein Array, das alle bisherigen Funktionsaufrufe in der Anfrage enthält. Ich werde mich nur auf die Schlüssel file
und line
in jedem Array konzentrieren.
Wie ich bereits sagte, handelt es sich bei den meisten davon um interne Framework-Aufrufe, was bedeutet, dass sich die meisten dieser Dateien in der Mitte unseres vendor/
-Verzeichnisses befinden. Das bedeutet, dass wir jede Datei
überprüfen und alle Aufrufe mit vendor/
wie folgt herausfiltern können:
Hier konvertiere ich das Array in eine Sammlung, um den filter zu verwenden
-Methode: Wenn die Datei
derzeit $trace
einen vendor/
hat, entfernen wir sie aus der Sammlung. Wenn Sie den obigen Code ausführen, sehen Sie etwa Folgendes:
Die Artikel sind viel weniger, wir sind von 63 auf nur 5 gestiegen. Das Beste daran ist, dass das erste Element in der Sammlung genau der Ort ist, an dem wir die SQL-Abfrage auslösen. Das bedeutet, dass wir diese Informationen extrahieren können, um die langsamsten Abfragen zu finden.
Drucken, um zu protokollierenDa wir jetzt alle Informationen haben, die wir brauchen, warum protokollieren wir sie nicht, damit wir die langsamsten Abfragen überprüfen und finden können? :
rrreee🎜Wenn Sie dies in Ihrer Anwendung verwenden, können Sie Ihre Protokolldateien überprüfen und Sie sollten Abfrageinformationen wie diese sehen:🎜rrreee🎜Jetzt wissen Sie, welche Abfragen am langsamsten sind, und beginnen mit der Verarbeitung nacheinander. Versuchen Sie, sie durchzuführen schneller, oder sie zumindest zwischenspeichern. 🎜🎜🎜🎜🎜Erweitertes Debugging🎜🎜🎜Dies eignet sich hervorragend zum Debuggen, aber diese Technik kann auf verschiedene Arten verwendet werden. 🎜🎜🎜Sie können einen wöchentlichen Bericht erstellen, der die langsamsten Abfragen der Woche zeigt. 🎜🎜🎜🎜Sie erhalten möglicherweise Slack-Benachrichtigungen, wenn eine Abfrage einen Zeitschwellenwert überschreitet. 🎜🎜🎜🎜 Sie können ein Dashboard erstellen, in dem Sie und Ihr Team jede ausgeführte Abfrage anzeigen können. 🎜🎜🎜Der Himmel ist die Grenze. 🎜🎜【Verwandte Empfehlungen: 🎜Laravel-Video-Tutorial🎜】🎜Das obige ist der detaillierte Inhalt vonEine kurze Analyse, wie man die langsamste Abfrage in Laravel findet. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!