7 days of WordPress plugins, themes & templates - for free!* Unlimited asset downloads! Start 7-Day Free Trial
Advertisement
  1. Code
  2. Ruby on Rails

Meningkatkan Kinerja Aplikasi Rails Anda dengan Eager Loading

Read Time: 12 mins

Indonesian (Bahasa Indonesia) translation by ⚡ Rova Rindrata (you can also view the original English article)

Pengguna menyukai aplikasi yang cepat, dan kemudian mereka jatuh cinta dengan mereka dan menjadikan mereka bagian dari kehidupan mereka. Aplikasi yang lambat, di sisi lain, hanya mengganggu pengguna dan kehilangan pendapatan. Dalam tutorial ini, kami akan memastikan bahwa kita tidak kehilangan lebih banyak uang atau pengguna, dan memahami berbagai cara untuk meningkatkan kinerja.

Active Records dan ORM adalah alat yang sangat kuat di Ruby on Rails, tetapi hanya jika kita tahu cara melepaskan dan menggunakan kekuatan tersebut. Pada awalnya, Anda akan menemukan banyak cara untuk melakukan tugas serupa dalam RoR, tetapi hanya ketika Anda menggali sedikit lebih dalam, Anda benar-benar mengetahui biaya menggunakan satu di atas yang lain.

Ini cerita yang sama dalam kasus ORM dan Associations di Rails. Mereka yakin membuat hidup kita lebih mudah, tetapi dalam beberapa situasi juga dapat bertindak sebagai berlebihan.

Mari Kita Ambil Sebuah Contoh

Tapi sebelum itu, mari kita segera membuat aplikasi dummy untuk bermain-main.

Langkah 1

Mulai terminal Anda dan ketikkan perintah ini untuk membuat aplikasi baru:

Langkah 2

Generate aplikasi Anda:

Langkah 3

Terapkan di server lokal Anda:

Dan itu dia! Sekarang Anda harus memiliki aplikasi dummy yang berjalan.

Ini adalah bagaimana kedua model kita (Author dan Post) harus terlihat. Kita memiliki Posts milik Author, dan kita memiliki Authors yang dapat memiliki banyak posting. Ini adalah asosiasi/relasi mendasar antara dua model yang akan kita mainkan.

Lihatlah "Controller Posts" Anda—ini adalah tampilan yang seharusnya. Fokus utama kita hanya pada metode indeksnya saja.

Dan yang tidak kalah penting, View Index Posts kita. Anda mungkin memiliki beberapa baris tambahan, tetapi ini adalah yang saya ingin Anda fokuskan, terutama baris dengan post.author.name.

Mari kita buat beberapa data dummy sebelum kita mulai. Pergi ke konsol rails Anda dan tambahkan baris berikut. Atau Anda bisa pergi ke http://localhost:3000/posts/new dan http://localhost:3000/authors/new untuk menambahkan beberapa data secara manual.

Sekarang Anda sudah siap, mari kita mulai server dengan rails s dan tekan localhost:3000/posts.

Anda akan melihat beberapa hasil di layar Anda seperti ini.

This image shows the page displaying all the PostsThis image shows the page displaying all the PostsThis image shows the page displaying all the Posts

Gambar ini menunjukkan halaman yang menampilkan semua PostingJadi semuanya tampak baik-baik saja: tidak ada kesalahan, dan itu mengambil semua record bersama dengan nama Author yang terkait. Tetapi jika Anda melihat log pengembangan Anda, Anda akan melihat banyak kueri yang dieksekusi seperti di bawah ini.

Yah, oke, saya setuju ini hanya empat kueri, tetapi bayangkan Anda memiliki 3.000 posting di database Anda, bukannya tiga. Dalam hal ini, database kita akan dibanjiri dengan 3.000+1 kueri, itulah sebabnya masalah ini disebut masalah N+1.

Mengapa Kita Mendapat Masalah Ini?

Jadi secara default di Ruby on Rails, ORM memiliki lazy loading diaktifkan, yang berarti penundaan pemuatan data sampai titik di mana kita benar-benar membutuhkannya.

Dalam kasus kita, pertama-tama adalah controller tempat ia diminta untuk mengambil semua posting.

Kedua adalah view, tempat kita mengulang melalui posting yang diambil oleh controller dan mengirim kueri untuk mendapatkan nama penulis untuk setiap posting secara terpisah. Oleh karena itulah masalah N+1.

Bagaimana Kita Memecahkan Masalahnya?

Untuk menyelamatkan kita dari situasi seperti itu, Rails menawarkan kita fitur yang disebut eager loading.

Eager loading memungkinkan Anda melakukan pramuat data terkait (penulis) untuk semua posting dari database, meningkatkan kinerja keseluruhan dengan mengurangi jumlah kueri, dan memberi Anda data yang ingin ditampilkan dalam view Anda, tetapi masalah di sini adalah yang mana yang digunakan. Gotcha!

Ya karena kita memiliki tiga dari mereka, dan semua melayani tujuan yang sama, tetapi tergantung pada kasusnya, salah satu dari mereka dapat terbukti mengurangi atau memberatkan kinerja lagi.

Sekarang Anda mungkin bertanya yang mana yang akan digunakan dalam kasus ini? Baiklah, mari kita mulai dengan yang pertama.

Simpan itu. Tekan URL lagi localhost:3000/posts.

This image shows the page displaying all the PostsThis image shows the page displaying all the PostsThis image shows the page displaying all the Posts

Gambar ini menunjukkan halaman yang menampilkan semua PostingJadi tidak ada perubahan dalam hasilnya: semuanya dimuat dengan cara yang persis sama, tetapi di bawah atap di log pengembangan, banyaknya kueri tersebut telah diubah menjadi dua berikut.

Pramuat menggunakan dua kueri terpisah untuk memuat data utama dan data terkait. Ini sebenarnya lebih baik daripada memiliki kueri terpisah untuk setiap nama penulis (Masalah N+1), tetapi ini tidak cukup bagi kita. Karena pendekatan kueri yang terpisah, itu akan melemparkan pengecualian dalam skenario seperti:

  1. Pengurutan posting berdasarkan nama penulis.
  2. Menemukan posting dari penulis "John" saja.

Mari Mencoba Semua Skenario dengan eager_load() Satu per Satu

1. Pengurutan Posting Berdasarkan Nama Penulis.

Kueri yang dihasilkan Dalam Log Pengembangan:

2. Menemukan Posting dari Penulis "John" Saja

Kueri yang dihasilkan Dalam Log Pengembangan:

3. Skenario N+1

Kueri yang dihasilkan Dalam Log Pengembangan:

Jadi jika Anda melihat kueri yang dihasilkan dari ketiga skenario, ada dua kesamaan.

Pertama, eager_load() selalu menggunakan LEFT OUTER JOIN, apa pun situasinya. Kedua, ia mendapat semua data yang terkait dalam satu kueri, yang pasti melampaui metode preload() dalam situasi di mana kita ingin menggunakan data terkait untuk tugas-tugas tambahan seperti pengurutan dan penyaringan. Tapi satu kueri dan LEFT OUTER JOIN juga bisa sangat mahal dalam skenario sederhana seperti di atas, di mana semua yang Anda butuhkan adalah menyaring para penulis yang diperlukan. Ini seperti menggunakan bazoka untuk membunuh lalat kecil.

Saya memahami bahwa ini hanyalah dua contoh sederhana, dan dalam skenario dunia nyata di luar sana, sangat sulit untuk memutuskan yang terbaik untuk situasi Anda. Jadi itulah alasan Rails memberi kita metode includes().

Dengan includes(), Active Record menangani keputusan yang sulit. Ini jauh lebih pintar daripada metode preload() dan eager_load() dan memutuskan yang mana yang akan digunakan sendiri.

Mari Mencoba Semua Skenario dengan includes()

1. Pengurutan Posting Berdasarkan Nama Penulis.

Kueri yang dihasilkan Dalam Log Pengembangan:

2. Menemukan Posting dari Penulis "John" Saja

Kueri yang dihasilkan Dalam Log Pengembangan:

3. Skenario N+1

Kueri yang dihasilkan Dalam Log Pengembangan:

Sekarang jika kita membandingkan hasilnya dengan metode eager_load(), dua kasus pertama memiliki hasil yang sama, tetapi dalam kasus terakhir ia dengan cerdas memutuskan untuk beralih ke metode preload() untuk kinerja yang lebih baik.

Luar biasa, Bukan?

Tidak, karena dalam lomba performa ini, terkadang eager loading juga bisa gagal. Saya harap beberapa dari Anda telah memperhatikan bahwa setiap kali metode eager loading menggunakan JOINS, mereka hanya menggunakan LEFT OUTER JOIN. Juga, dalam setiap kasus mereka memuat terlalu banyak data yang tidak perlu dalam memori—mereka memilih setiap kolom dari tabel, sedangkan kita hanya membutuhkan nama penulis.

Selamat datang di Joins

Meskipun Active Record memungkinkan Anda menentukan kondisi pada asosiasi eager load sama seperti joins(), cara yang disarankan adalah menggunakan joins sebagai gantinya. ~ Dokumentasi Rails.

Seperti yang direkomendasikan dalam dokumentasi rails, metode joins() adalah selangkah lebih maju dalam situasi ini. Ini menggabungkan dengan tabel terkait, tetapi hanya memuat data model yang diperlukan ke dalam memori seperti posting dalam kasus kita. Oleh karena itu, kita tidak memuat data yang berlebihan ke dalam memori yang sia-sia—meskipun jika kita ingin kita dapat melakukannya juga.

Mari Selami Beberapa Contoh

1. Pengurutan Posting Berdasarkan Nama Penulis

Kueri yang dihasilkan Dalam Log Pengembangan:

2. Menemukan Posting dari Penulis "John" Saja

Kueri yang dihasilkan Dalam Log Pengembangan:

3. Skenario N+1

Kueri yang dihasilkan Dalam Log Pengembangan:

Hal pertama yang Anda perhatikan dari hasil di atas adalah bahwa kembalinya masalah N+1, tetapi mari kita fokus pada bagian yang baik terlebih dahulu.

Mari kita lihat kueri pertama dari semua hasil. Semuanya terlihat kurang lebih seperti ini.

Ini mengambil semua kolom dari posting. Ini menggabungkan kedua tabel dengan baik dan menyortir atau menyaring record tergantung pada kondisi, tetapi tanpa mengambil data dari tabel terkait. Itulah yang kami inginkan sejak awal.

Tapi setelah kueri pertama, kita akan melihat 1 atau 3 atau sejumlah N kueri tergantung pada data dalam database Anda, seperti ini:

Sekarang Anda mungkin bertanya: mengapa masalah N+1 ini kembali? Ini karena baris ini dalam view post.author.name kita.

Baris ini memicu semua kueri itu. Jadi dalam contoh di mana kita hanya perlu mengurutkan posting kita, kita tidak perlu menampilkan nama penulis dalam view kita. Dalam hal ini kita dapat memperbaiki masalah ini dengan menghapus baris post.author.name dari view.

Tetapi kemudian Anda mungkin bertanya, "Hai, MK, bagaimana dengan contoh di mana kita ingin menampilkan nama penulis dalam view?"

Nah, dalam hal ini, metode joins() tidak akan memperbaikinya dengan sendirinya. Kita harus memberitahu joins() untuk memilih nama penulis, atau kolom lain dari tabel untuk masalah ini. Dan kita bisa melakukannya dengan menambahkan pernyataan select() di bagian akhir, seperti ini:

Saya membuat alias "author_name" untuk authors.name. Kita akan melihat alasannya sebentar lagi.

Kueri yang dihasilkan Dalam Log Pengembangan:

Di sini kita: akhirnya kueri SQL yang bersih tanpa masalah N+1, tanpa data yang tidak diperlukan, hanya dengan hal-hal yang kita butuhkan. Satu-satunya yang tersisa adalah menggunakan alias itu dalam view Anda dan mengubah post.author.name menjadi post.author_name. Ini karena author_name sekarang menjadi atribut dari model Post kita, dan setelah perubahan ini adalah bagaimana halaman terlihat:

This image shows the page displaying all the PostsThis image shows the page displaying all the PostsThis image shows the page displaying all the Posts

Semuanya persis sama, tetapi di bawah atap banyak hal telah berubah. Jika saya menempatkan semuanya secara singkat, untuk menyelesaikan N+1 Anda harus menggunakan eager loading, tetapi kadang-kadang, tergantung pada situasinya, Anda harus mengambil hal-hal dalam kendali Anda dan menggunakan joins untuk opsi yang lebih baik. Anda juga dapat menyediakan kueri SQL mentah ke metode joins() untuk penyesuaian lebih lanjut.

Penggabungan dan eager loading juga memungkinkan pemuatan banyak asosiasi, tetapi pada awalnya semuanya menjadi sangat rumit dan sulit untuk memutuskan opsi terbaik. Dalam situasi seperti itu, saya sarankan Anda membaca dua tutorial Envato Tuts+ yang sangat bagus ini untuk mendapatkan pemahaman yang lebih baik tentang penggabungan dan dapat memutuskan pendekatan yang paling murah dalam hal kinerja:

Yang tidak kalah penting, itu bisa rumit untuk mengetahui area dalam aplikasi pra-build Anda di mana Anda harus meningkatkan kinerja secara umum atau menemukan masalah N+1. Dalam kasus-kasus itu saya merekomendasikan gem yang bagus yang disebut Bullet. Ini dapat memberitahu Anda ketika Anda harus menambahkan eager loading untuk kueri-kueri N+1, dan ketika Anda menggunakan eager loading yang tidak perlu.

Advertisement
Did you find this post useful?
Want a weekly email summary?
Subscribe below and we’ll send you a weekly email summary of all new Code tutorials. Never miss out on learning about the next big thing.
Advertisement
Scroll to top
Looking for something to help kick start your next project?
Envato Market has a range of items for sale to help get you started.