Votre site Web est-il lent ? Est-ce que le chargement est long ? Les utilisateurs se plaignent-ils du fait qu'il est presque inutilisable ? Vous devriez vérifier vos requêtes de base de données. Je vais vous montrer une manière intéressante d'analyser facilement toutes vos requêtes de base de données.
Bien sûr, il existe de nombreuses raisons pour lesquelles votre site Web peut être lent, mais l'une des raisons les plus courantes est la lenteur des requêtes dans la base de données.
Mais dans Laravel, nous n'utilisons (la plupart du temps) pas SQL pour obtenir des données de la base de données, nous utilisons Eloquent ORM et Query Builder, ce qui rend parfois difficile l'identification de la requête qui provoque la création de notre site. sois si lent.
Heureusement, dans Laravel, nous pouvons définir un rappel qui est appelé à chaque fois qu'une requête est exécutée (voir ici). Pour ce faire, ajoutez le code suivant à n'importe quel fournisseur de services (par exemple AppServiceProvider) :
public function boot() { DB::listen(function ($query) { // TODO: make this useful }); }
Comme vous pouvez le voir, nous recevons une variable $query
qui est Une instance de la classe 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/
. Cela signifie que nous avons accès à certaines informations sur la requête exécutée :
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 }
C'est une information très utile, nous pouvons maintenant identifier les requêtes lentes en regardant l'attribut $query->time
.
.
Même si la variable $query
ne nous donne aucune information sur son origine, nous pouvons toujours obtenir ces informations en utilisant la fonction intégrée 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']} ------------ "); }); }
Si vous exécutez ceci sur votre projet, vous verrez quelque chose comme ceci sur le navigateur :
[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 ----------
Il s'agit d'un tableau contenant tous les appels de fonction jusqu'à présent dans la requête. Je vais juste me concentrer sur les clés file
et line
dans chaque tableau.
Comme je l'ai déjà dit, la plupart d'entre eux sont des appels de framework internes, ce qui signifie que la plupart de ces fichiers se trouvent au milieu de notre répertoire vendor/
. Cela signifie que nous pouvons vérifier chaque fichier
et filtrer tous les appels avec vendor/
comme ceci :
Ici, je convertis le tableau en collection en utilisant le filter
, si le fichier
actuellement $trace
a un fournisseur/
nous le supprimons de la collection. Si vous exécutez le code ci-dessus vous verrez quelque chose comme ceci :
Les articles sont beaucoup moins nombreux, nous sommes passés de 63 à seulement 5. La meilleure partie est que le premier élément de la collection est l'emplacement exact où nous déclenchons la requête SQL. Cela signifie que nous pouvons extraire ces informations pour trouver les requêtes les plus lentes.
Print to LogMaintenant que nous avons toutes les informations dont nous avons besoin, pourquoi ne pas les enregistrer afin que nous puissions inspecter et trouver les requêtes les plus lentes ? :
rrreee🎜Si vous l'utilisez dans votre application, vous pouvez vérifier vos fichiers journaux et vous devriez voir des informations de requête comme celle-ci :🎜rrreee🎜Vous savez maintenant quelles requêtes sont les plus lentes et commencez à les traiter une par une, essayez de les faire plus rapidement, ou au moins les mettre en cache. 🎜🎜🎜🎜🎜Débogage étendu🎜🎜🎜C'est idéal pour le débogage, mais cette technique peut être utilisée de différentes manières. 🎜🎜🎜Vous pouvez créer un rapport hebdomadaire montrant les requêtes les plus lentes de la semaine. 🎜🎜🎜🎜Vous pouvez recevoir des alertes Slack si une requête dépasse un seuil de temps 🎜🎜🎜🎜 Vous pouvez créer un tableau de bord où vous et votre équipe pouvez voir chaque requête exécutée 🎜🎜🎜Le ciel est la limite. 🎜🎜【Recommandation associée : 🎜tutoriel vidéo laravel🎜】🎜Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!