Memperbaiki Query Lambat di Endpoint SvelteKit
Query lambat sering muncul saat endpoint SvelteKit memanggil database dengan filter atau urutan yang tidak cocok dengan struktur penyimpanan. Untuk tim yang menghadapi masalah tersebut, solusi utamanya adalah mengidentifikasi query bermasalah, memastikan indeks database mendukung pola filter/urut, dan menghindari pagination offset yang mengabaikan seberapa cepat pertumbuhan data. Artikel ini langsung menunjukkan langkah teknis untuk memperbaiki jalur tersebut.
Identifikasi Query Bermasalah
Mulailah dengan mencatat durasi query dari middleware atau observability. Jika Anda menggunakan database seperti PostgreSQL atau MySQL, aktifkan slow query log atau gunakan fitur EXPLAIN ANALYZE untuk melihat rencana eksekusi. Fokus pada endpoint-endpoint SvelteKit yang menggabungkan filter dengan urutan, misalnya API berita yang mengurut berdasarkan created_at.
Langkah praktis:
- Tambahkan logging di
+server.tsatau service database untuk mencatat parameter dan waktu mulai/selesai. - Jalankan
EXPLAINpada query yang paling lama responnya dan perhatikan apakah database melakukan table scan. - Cek apakah SvelteKit mengirim parameter pagination seperti
pageataucursordengan nilai kosong, karena itu bisa memicu fallback ke full scan.
Catat pola filter dan urutan yang paling sering dipakai. Query yang lambat biasanya dilatarbelakangi oleh kolom filter yang tidak diindeks atau oleh penggunaan pagination offset yang memaksa database menghitung ulang ribuan baris.
Menentukan Index Efektif pada Database Relasional
Setelah mengetahui pola akses, buat index yang mendukung WHERE dan ORDER BY Anda. Di database relasional, index berfungsi sebagai shortcut untuk menemukan baris sesuai kondisi tanpa memindai seluruh tabel.
Pertimbangan saat memilih index
- Urutan kolom di index: taruh kolom yang ada di
WHEREdi depan. Jika query Anda adalahWHERE published = true ORDER BY created_at DESC, index yang pas adalah(published, created_at DESC). - Index komposit lebih efisien daripada beberapa index terpisah, asalkan urutan kolom mencerminkan pola query.
- Biaya tulis: setiap index tambahan memperlambat operasi INSERT/UPDATE. Hitung trade-off antara kecepatan baca dan beban tulis.
Gunakan pg_stat_user_indexes (PostgreSQL) atau SHOW INDEX (MySQL) untuk mengecek apakah index digunakan. Jika masih terjadi table scan, periksa apakah query mengekspresikan kondisi tambahan seperti fungsi pada kolom, karena itu bisa mengabaikan index.
Implementasi Cursor Pagination pada Endpoint
Pagination offset menyebabkan database membaca baris hingga offset tertentu, sehingga lambat saat data tumbuh. Cursor pagination menghindari hal ini dengan selalu mengambil data setelah posisi terakhir.
Contoh SvelteKit +server.ts yang menerima cursor dan limit, lalu menjalankan query index-friendly:
import type { RequestHandler } from './$types';
import { db } from '$lib/db';
export const GET: RequestHandler = async ({ url }) => {
const cursor = url.searchParams.get('cursor');
const limit = Math.min(Number(url.searchParams.get('limit') ?? 20), 100);
const params = cursor
? cursor.split(',').map((value) => value.trim())
: [new Date().toISOString(), Number.MAX_SAFE_INTEGER];
const rows = await db.query(
`SELECT id, title, updated_at
FROM articles
WHERE (updated_at, id) < ($1::timestamp, $2::bigint)
ORDER BY updated_at DESC, id DESC
LIMIT $3`,
[...params, limit]
);
const nextCursor = rows.length === limit
? `${rows.at(-1)?.updated_at},${rows.at(-1)?.id}`
: null;
return new Response(JSON.stringify({ data: rows, nextCursor }), { headers: { 'Content-Type': 'application/json' } });
};Pastikan tabel memiliki index komposit pada kolom (updated_at DESC, id DESC). Karena cursor mengekspresikan kondisi rangkap, index ini memungkinkan database langsung menempatkan pointer ke posisi yang cocok dan membaca limit baris berikutnya.
Untuk bagian frontend, contoh load function SvelteKit memanfaatkan endpoint di atas:
export const load = async ({ fetch, url }) => {
const cursor = url.searchParams.get('cursor');
const params = new URLSearchParams({ limit: '25' });
if (cursor) params.set('cursor', cursor);
const res = await fetch(`/api/articles?${params.toString()}`);
const payload = await res.json();
return {
articles: payload.data,
nextCursor: payload.nextCursor
};
};Dengan pola ini, client selalu meminta batch berikutnya berdasarkan cursor terakhir tanpa menyebut nomor halaman. API memberi tahu nextCursor, dan SvelteKit mempertahankan state tersebut di URL atau store.
Metrik Observability untuk Memantau Bottleneck SQL
Observability membantu memastikan perbaikan berjalan sesuai harapan. Catat metrik berikut:
- Durasi query: rata-rata waktu eksekusi query endpoint yang relevan. Jika terus naik, itu indikator index tidak bekerja.
- Rows returned vs rows scanned: rasio ini menandakan apakah query membaca jauh lebih banyak baris daripada yang dikembalikan.
- Hit ratio index: pada PostgreSQL,
pg_stat_user_tablesmenampilkan jumlah scan sequential vs index. Naikkan hit ratio dengan index yang cocok.
Gunakan middleware SvelteKit untuk mencatat durasi fetch, atau pasang setInterval di backend untuk menulis metrik ke observability stack seperti Prometheus. Jika angka durasi meningkat bersamaan dengan pertumbuhan data, telusuri apakah urutan kursornya konsisten dengan index, atau apakah parameter limit dibatasi terlalu tinggi.
Kesimpulan dan Praktik Lanjutan
Memperbaiki query lambat di SvelteKit menuntut pendekatan holistik: identifikasi query bermasalah, pilih index sesuai pola akses, dan gunakan cursor pagination agar pertumbuhan data tidak mengorbankan performa. Jangan lupa memantau metrik SQL untuk menangkap degradasi lebih awal.
Setelah menyelesaikan langkah ini, pertimbangkan untuk menambah caching read-heavy, meninjau strategi vacuum/analyze pada database, dan mengotomatiskan pengecekan index usage. Dengan demikian, endpoint SvelteKit tetap responsif sewaktu beban dan volume data meningkat.
Komentar
0 komentar
Masuk ke akun kamu untuk ikut berkomentar.
Belum ada komentar
Jadilah yang pertama ikut berdiskusi!