Heim > PHP-Framework > Laravel > Eine kurze Analyse, wie man die langsamste Abfrage in Laravel findet

Eine kurze Analyse, wie man die langsamste Abfrage in Laravel findet

青灯夜游
Freigeben: 2022-09-08 10:09:00
nach vorne
2496 Leute haben es durchsucht

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.

Eine kurze Analyse, wie man die langsamste Abfrage in Laravel findet

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.

DB::listen()

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
    });
}
Nach dem Login kopieren

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; // 执行查询所用的时间;
 });
Nach dem Login kopieren

这是非常有用的信息,现在我们可以通过查看 $query->time 属性来识别慢查询。 但这并没有告诉我们在我们的代码中查询执行的位置

我怎么知道查询是在哪里执行的?

即使该 $query 变量没有给我们任何关于其来源的信息, 我们仍然可以使用 PHP 内置函数  debug_backtrace() 获取该信息。

DB::listen(function ($query) {
    dd(debug_backtrace());
});
Nach dem Login kopieren

如果你在你的项目上运行它,你会在浏览器上看到类似这样的东西:

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 [▶]
  ]
  ....
Nach dem Login kopieren

这是一个数组,其中包含请求中到目前为止的每个函数调用。我将只关注每个数组中的 fileline 键。

如果你仔细看,你会发现在我的例子中有 63 个函数调用,这是一个简单的应用程序,如果在更复杂的应用程序中,可能会更多。更糟糕的是,如果您查看顶部的那些, 它们都是 laravel 框架的内部函数。我们是否应该逐一查看,直到找到可能对我们有帮助的东西?

查找查询位置

正如我之前所说,它们中的大多数是内部框架调用,这意味着这些文件中的大多数都在我们的 vendor/ 目录中。这意味着我们可以检查每个 file 并过滤掉任何具有 vendor/ 的调用,如下所示:

DB::listen(function ($query) {
    $stackTrace = collect(debug_backtrace())->filter(function ($trace) {
        return !str_contains($trace['file'], 'vendor/');
    });

    dd($stackTrace);
});
Nach dem Login kopieren

在这里,我将数组转换为集合以使用该 filter 方法,如果 file 当前 $tracevendor/-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
}
Nach dem Login kopieren

Das sind sehr nützliche Informationen. Jetzt können wir langsame Abfragen identifizieren, indem wir uns das Attribut $query->time ansehen.

Aber das sagt uns nicht, wo in unserem Code die Abfrage ausgeführt wird

.

Woher weiß ich, wo die Abfrage ausgeführt wurde?

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']}
            ------------
        ");
    });
}
Nach dem Login kopieren

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
----------
Nach dem Login kopieren

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.

Wenn Sie genau hinsehen, werden Sie feststellen, dass es in meinem Beispiel 63 Funktionsaufrufe gibt. Dies ist eine einfache Anwendung, in einer komplexeren Anwendung könnten es jedoch mehr sein. Schlimmer noch, wenn Sie sich die oben genannten ansehen, das sind alles interne Funktionen des Laravel-Frameworks. Sollten wir uns jeden einzelnen anschauen, bis wir etwas finden, das uns helfen könnte?

Abfrageorte finden

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:

rrreee

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:

rrreee

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 protokollieren

Da 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!

Verwandte Etiketten:
Quelle:learnku.com
Erklärung dieser Website
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn
Beliebte Tutorials
Mehr>
Neueste Downloads
Mehr>
Web-Effekte
Quellcode der Website
Website-Materialien
Frontend-Vorlage