Rumah  >  Artikel  >  rangka kerja php  >  Analisis ringkas tentang cara mencari pertanyaan paling perlahan dalam Laravel

Analisis ringkas tentang cara mencari pertanyaan paling perlahan dalam Laravel

青灯夜游
青灯夜游ke hadapan
2022-09-08 10:09:002462semak imbas

Adakah tapak web anda lambat? Adakah ia mengambil masa yang lama untuk memuatkan? Adakah pengguna mengadu bahawa ia hampir tidak boleh digunakan? Anda harus menyemak pertanyaan pangkalan data anda. Saya akan menunjukkan kepada anda cara yang kemas untuk menganalisis semua pertanyaan pangkalan data anda dengan mudah.

Analisis ringkas tentang cara mencari pertanyaan paling perlahan dalam Laravel

Sudah tentu, terdapat banyak sebab tapak web anda mungkin lambat, tetapi salah satu sebab yang paling biasa ialah pertanyaan pangkalan data yang perlahan.

Tetapi dalam laravel kami (kebanyakan masa) tidak menggunakan SQL untuk mendapatkan data daripada pangkalan data, kami menggunakan Eloquent ORM dan Query Builder yang kadang-kadang Ini menjadikan sukar untuk menentukan pertanyaan yang menyebabkan tapak kami menjadi begitu perlahan.

DB::listen()

Nasib baik, dalam laravel, kita boleh mentakrifkan fungsi yang dipanggil setiap kali pertanyaan dilaksanakan panggil balik (lihat di sini). Untuk melakukan ini, tambahkan kod berikut pada mana-mana pembekal perkhidmatan (cth. AppServiceProvider):

public function boot()
{
    DB::listen(function ($query) {
    // TODO: make this useful
    });
}

Seperti yang anda lihat, kami menerima pembolehubah $query iaitu QueryExecuted Satu contoh daripada kelas. Ini bermakna kami mempunyai akses kepada beberapa maklumat tentang pertanyaan yang dilaksanakan:

 DB::listen(function ($query) {
     $query->sql; // 执行的 sql 字符串
     $query->bindings; // 传递给sql查询的参数(这将替换sql字符串中的 "?")
     $query->time; // 执行查询所用的时间;
 });

Ini adalah maklumat yang sangat berguna, kini kami boleh mengenal pasti pertanyaan perlahan dengan melihat atribut $query->time. Tetapi ini tidak memberitahu kami di mana dalam kod kami pertanyaan dilaksanakan.

Bagaimanakah saya tahu di mana pertanyaan itu dilaksanakan?

Walaupun pembolehubah $query tidak memberi kami sebarang maklumat tentang asalnya, kami masih boleh mendapatkan maklumat tersebut menggunakan fungsi terbina dalam PHP debug_backtrace() .

DB::listen(function ($query) {
    dd(debug_backtrace());
});

Jika anda menjalankan ini pada projek anda, anda akan melihat sesuatu seperti ini pada penyemak imbas anda:

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 [▶]
  ]
  ....

Ini ialah tatasusunan dengan nilai dalam permintaan setiap panggilan fungsi setakat ini. Saya hanya akan menumpukan pada kekunci file dan line dalam setiap tatasusunan.

Jika anda melihat dengan teliti anda akan melihat bahawa dalam kes saya terdapat 63 panggilan fungsi, ini adalah aplikasi yang mudah, jika dalam aplikasi yang lebih kompleks ia boleh menjadi lebih. Lebih teruk, jika anda melihat yang di atas, semuanya adalah fungsi dalaman rangka kerja laravel. Patutkah kita melihat setiap satu sehingga kita menemui sesuatu yang boleh membantu kita?

Cari lokasi pertanyaan

Seperti yang saya katakan sebelum ini, kebanyakannya adalah panggilan rangka kerja dalaman, yang bermaksud dalam fail ini Kebanyakannya berada dalam vendor/ direktori. Ini bermakna kita boleh menyemak setiap file dan menapis sebarang panggilan dengan vendor/ seperti ini:

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

    dd($stackTrace);
});

Di sini saya menukar tatasusunan kepada koleksi untuk menggunakan Kaedah filter itu, jika file pada masa ini $trace mempunyai vendor/ kami mengeluarkannya daripada set.

Jika anda menjalankan kod di atas, anda akan melihat sesuatu seperti ini:

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
}

Item adalah jauh lebih sedikit, kami bertukar daripada 63 kepada 5 sahaja. Bahagian yang terbaik ialah item pertama dalam koleksi ialah lokasi tepat di mana kami mencetuskan pertanyaan SQL. Ini bermakna kita boleh mengekstrak maklumat ini untuk mencari pertanyaan yang paling perlahan.

Cetak untuk log

Sekarang kami mempunyai semua maklumat yang kami perlukan, mengapa tidak logkannya supaya kami boleh menyemak dan mencari yang paling lambat Siasatan? :

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']}
            ------------
        ");
    });
}

Jika anda menggunakan ini dalam aplikasi anda, anda boleh menyemak fail log anda dan anda sepatutnya melihat maklumat pertanyaan seperti ini:

[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
----------

Sekarang anda tahu pertanyaan mana yang paling perlahan dan mula memprosesnya satu demi satu, cuba menjadikannya lebih pantas, atau sekurang-kurangnya cachenya.

Penyahpepijat Lanjutan

Ini berguna untuk nyahpepijat, tetapi teknik ini boleh digunakan dalam pelbagai cara.

Anda boleh membuat laporan mingguan yang menunjukkan pertanyaan paling perlahan dalam seminggu.

Anda mungkin menerima makluman kendur jika pertanyaan melebihi ambang masa

Anda boleh mencipta papan pemuka yang anda dan pasukan anda boleh Lihat setiap pertanyaan dilaksanakan di dalamnya

Langit adalah hadnya.

[Cadangan berkaitan: tutorial video laravel]

Atas ialah kandungan terperinci Analisis ringkas tentang cara mencari pertanyaan paling perlahan dalam Laravel. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!

Kenyataan:
Artikel ini dikembalikan pada:learnku.com. Jika ada pelanggaran, sila hubungi admin@php.cn Padam
Artikel sebelumnya:Adakah laravel aop?Artikel seterusnya:Adakah laravel aop?