Memburu N+1 dan Menghapuskan Kueri yang Membazir dalam Laravel

Kerja prestasi selalunya membosankan.

Ia tidak selalunya tentang kisah wira di mana anda mengurangkan kependaman (latency) sebanyak 80%. Kebanyakan hari, ia adalah tentang pembersihan. Anda menemui kueri yang anda tidak sedar sedang dijalankan. Kemudian, anda memadamkannya.

Jika aplikasi Laravel anda semakin berkembang, anda berkemungkinan menghadapi tiga masalah ini.

  1. Kueri N+1 yang Tersembunyi

Anda tidak boleh membaiki apa yang anda tidak nampak. Gunakan alat seperti beyondcode/laravel-query-detector dalam persekitaran tempatan (local environment) anda. Ia akan memberitahu anda apabila anda menggunakan corak loop-and-lazy-load.

Jangan jalankan ini dalam pengeluaran (production). Ia menambah beban (overhead). Hanya daftarkannya apabila aplikasi anda berada dalam mod tempatan atau ujian.

  1. Pembaziran Eager Loading

Orang sering menyelesaikan masalah N+1 dengan menambah with(). Tetapi ini mewujudkan masalah baharu. Anda mungkin melakukan eager-load pada hubungan (relationship) yang tidak lagi digunakan oleh paparan (view) anda.

Jika reka bentuk semula membuang sesuatu lajur daripada jadual, anda mesti membuang panggilan with() yang berkaitan dalam pengawal (controller) anda. Anda membayar untuk data yang anda buang begitu sahaja.

Anggap setiap eager load sebagai satu tuntutan. Jika anda tidak menggunakan data tersebut, buang tuntutan itu.

  1. Mengira Semula Data yang Sama

Sesetengah nilai kekal sama sepanjang permintaan (request). Jika anda mengiranya berkali-kali, anda membazirkan CPU. Gunakan memoization untuk menyelesaikannya.

Contoh:

protected ?string $defaultConnection = null;

public function getDefaultConnectionName(): string
{
    return $this->defaultConnection ??= $this->resolveDefaultConnection();
}

Operator ??= mengira nilai tersebut sekali sahaja dan menggunakannya semula untuk baki permintaan tersebut.

  1. Perangkap Kueri Papan Pemuka (Dashboard)

Papan pemuka selalunya menjalankan kueri count() yang berasingan untuk setiap kad. Jika anda mempunyai enam kad, anda menjalankan enam kueri.

Sebaliknya, lakukan dua perkara ini:

  • Kumpulkan jumlah (counts) anda. Dapatkan semua jumlah untuk satu jadual dalam satu kueri tunggal.
  • Gunakan cache jangka pendek. Statistik papan pemuka tidak perlu dikemas kini setiap saat. Simpan dalam cache selama lima minit.

Seorang pelawat menanggung kos kueri tersebut. Orang lain akan mendapat hasil daripada cache.

Tip Terakhir: Cegah Regresi

Proses pembersihan akan gagal jika pembangun menambah semula kod yang buruk kemudian hari. Gunakan Pest untuk mengesahkan (assert) jumlah kueri anda. Tetapkan had maksimum untuk jumlah kueri yang boleh dijalankan oleh sesuatu halaman. Jika pembangun menambah N+1, ujian tersebut akan gagal.

Pengoptimuman kebanyakannya adalah tentang pembuangan. Buang load yang tidak digunakan. Buang nilai yang dikira semula. Buang kueri yang tidak perlu.

Sumber: https://dev.to/nasrulhazim/a-day-of-performance-hardening-hunting-n1s-and-killing-wasted-queries-in-laravel-568p