SQL Anda Laju Tetapi API Anda Perlahan
Pertanyaan pangkalan data anda laju. Caching anda berfungsi. Tugasan latar belakang (background jobs) anda dalam keadaan baik.
Namun, API anda masih perlahan. Penggunaan CPU anda tinggi.
Masalahnya bukan pada pangkalan data anda. Masalahnya adalah pada lapisan Ruby.
Kesesakan (bottleneck) sering berlaku selepas data keluar dari pangkalan data dan masuk ke dalam aplikasi anda. Ini berlaku melalui tiga isu utama:
- Penserialan yang berlebihan (Bloated serialization)
- Peruntukan objek yang berlebihan (Excessive object allocation)
- Pengiraan berulang (Repeated computation)
Berikut adalah cara untuk memperbaikinya.
- Hentikan Penserialan yang Berlebihan
Ramai pembangun menukarkan keseluruhan model kepada JSON.
render json: @shipments
Jika satu penghantaran mempunyai 40 lajur tetapi frontend anda hanya memerlukan 5, anda membazirkan kitaran CPU. Anda juga berisiko membocorkan data peribadi seperti kunci API atau kos.
Cara penyelesaian: pulangkan hanya medan yang anda perlukan.
render json: @shipments.as_json(only: [:id, :tracking_no, :status])
Untuk kelajuan yang lebih baik, gunakan pluck untuk mengambil data sebagai tatasusunan (arrays). Ini mengelakkan pembinaan objek ActiveRecord yang berat sepenuhnya.
- Kurangkan Peruntukan Objek
Setiap objek yang dicipta oleh Ruby memerlukan memori. Mencipta beribu-ribu objek semasa satu permintaan (request) memaksa Garbage Collector (GC) bekerja lebih keras. Ini melambatkan keseluruhan sistem anda.
Elakkan membina hash atau string baharu di dalam gelung (loops).
Buruk:
@shipments.map do |s|
{ label: "#{s.tracking_no} - #{s.status.upcase}" }
end
Baik: Alihkan data statik ke luar gelung. Lakukan lebih banyak kerja di dalam pangkalan data berbanding di dalam Ruby.
- Elakkan Pengiraan Berulang
Jika anda memanggil kaedah (method) yang sama berulang kali dalam satu permintaan, anda membazirkan masa.
Contoh:
def total_weight
shipments.sum(&:weight)
end
Jika view, helper, dan serializer anda semuanya memanggil ini, anda mengira jumlah tersebut sebanyak tiga kali.
Cara penyelesaian: gunakan memoization.
def total_weight
@total_weight ||= shipments.sum(&:weight)
end
Ini memastikan pengiraan matematik hanya berlaku sekali bagi setiap permintaan.
Jadual Ringkasan:
- Penserialan berlebihan: Pulangkan hanya medan yang diperlukan atau gunakan
pluck. - Peruntukan tinggi: Bina lebih sedikit objek di dalam gelung.
- Pengiraan berulang: Gunakan memoization untuk menggunakan semula hasil.
Pengoptimuman pangkalan data bermaksud meminta kurang data. Pengoptimuman aplikasi bermaksud melakukan kurang kerja remeh (busywork) sebaik sahaja anda mendapat data tersebut.
Sumber: https://dev.to/danewu/your-sql-is-fast-but-the-api-is-slow-its-the-ruby-layer-2fno
