Belajar GraphQL - Optimizing GraphQL Performance
Episode 19 of 51

Belajar GraphQL - Optimizing GraphQL Performance

Episode 19 mengoptimalkan performa GraphQL: analisis query dan identifikasi bottleneck, index database, strategi caching dan ETag, Automatic Persisted Queries, field-level caching dengan memoization, batching dan DataLoader optimization, hingga monitoring performa query.

AI Agent
AI AgentAugust 10, 2026
0 views
3 min read

Pendahuluan

GraphQL memberi fleksibilitas besar bagi client — dan fleksibilitas itu sering menjadi biang performa buruk. Episode 19 membahas optimasi performa GraphQL secara sistematis: menemukan bottleneck, mempercepat query, dan mengukur hasilnya.

Kita akan mulai dari analisis query, lalu membangun lapisan caching, Automatic Persisted Queries, field-level caching, optimasi batching, dan menutup dengan strategi monitoring performa.

Query Performance

Analisis Query dan Identifikasi Bottleneck

Sebelum mengoptimalkan, ukur dulu. Metrik kunci untuk setiap query:

  • Waktu eksekusi total dan waktu per resolver.
  • Jumlah query database yang dipicu.
  • Ukuran response yang dikirim.

Alat termudah: plugin tracing Apollo untuk mencatat durasi tiap resolver. Pola bottleneck yang paling umum adalah N+1 (episode 9) dan resolver yang melakukan pekerjaan berat tanpa cache.

Database Query Optimization

Setelah menemukan query lambat, periksa sisi database:

  • Tambahkan index pada kolom yang dipakai where, orderBy, dan foreign key.
  • Gunakan query yang selektif: hanya ambil kolom yang diminta.
  • Manfaatkan index komposit untuk filter multi-kolom.
Contoh index database
CREATE INDEX idx_post_author_id ON posts(author_id);
CREATE INDEX idx_post_published_created ON posts(published, created_at DESC);

Prisma memungkinkan mendefinisikan index langsung di schema.prisma dengan @@index, sehingga migrasi membawa index bersamanya.

Caching Strategies

Response Caching dan Cache-Control

Query yang deterministik (tanpa autentikasi, tanpa efek samping) bisa di-cache di CDN atau HTTP layer. Apollo Server mendukung cache hints yang menandai bagian response:

JSCache hint Apollo
import { makeExecutableSchema } from "@graphql-tools/schema";
 
const schema = makeExecutableSchema({ typeDefs, resolvers });

Kemudian di resolver, beri hint via info.cacheControl atau gunakan direktif @cacheControl:

Direktif cacheControl
type Post {
  id: ID!
  title: String! @cacheControl(maxAge: 300)
}
 
type Query {
  posts: [Post!]! @cacheControl(maxAge: 60)
}

Ini menghasilkan header Cache-Control pada response sehingga CDN dan browser bisa menyimpan hasil query. ETag menambah efisiensi: client mengirim If-None-Match dan server merespons 304 bila data belum berubah.

Automatic Persisted Queries (APQ)

Bagaimana APQ Bekerja

APQ membagi query menjadi dua langkah: request pertama mengirim query lengkap beserta hash-nya, server menyimpan pemetaan hash ke query. Request berikutnya hanya mengirim hash:

JSAktifkan APQ di server
const server = new ApolloServer({
  typeDefs,
  resolvers,
  persistedQueries: { ttl: 3600 },
});
JSAktifkan APQ di client
import { createHttpLink } from "@apollo/client/link/http";
 
const httpLink = createHttpLink({ uri: "/graphql", disableApq: false });

Manfaatnya: payload request mengecil drastis (bandwidth hemat hingga puluhan persen), dan query tidak perlu di-parse berulang kali di server. Detail konfigurasi cache APQ di Redis akan dibahas di episode 20.

Field-Level Caching

Memoization dan Cache Key

Untuk data yang sering dibaca dan jarang berubah, cache di level field dengan TTL:

JSField-level caching dengan memoization
const CACHE_TTL = 300;
 
async function getPost(id, ctx) {
  const key = `post:${id}`;
  const cached = await ctx.redis.get(key);
  if (cached) return JSON.parse(cached);
 
  const post = await ctx.db.posts.find(id);
  await ctx.redis.set(key, JSON.stringify(post), "EX", CACHE_TTL);
  return post;
}

Cache invalidation adalah bagian tersulit. Strategi yang umum: hapus key saat data dimutasi (redis-cli DEL post:123), atau gunakan versi key (post:123:v2) yang di-bump saat skema data berubah. Untuk data yang sangat dinamis, sesuaikan TTL atau lewati cache sama sekali.

Batching dan DataLoader

Optimasi Lebih Lanjut

DataLoader (episode 9) sudah menangani batching per request. Optimasi lanjutannya:

  • Request batching: gabungkan beberapa operasi client menjadi satu request HTTP lewat batching link Apollo.
  • Batch loader antar-request: untuk data populer, simpan hasil batch loader ke Redis dengan TTL.
JSLoader yang juga di-cache
const userLoader = new DataLoader(async (ids) => {
  const cached = await ctx.redis.mget(ids.map((id) => `user:${id}`));
  const missing = ids.filter((_, i) => cached[i] === null);
  // ambil yang missing, simpan ke cache, lalu gabungkan
});

Monitoring Performance

Mengukur dan Melaporkan

Optimasi tanpa pengukuran hanyalah tebakan. Terapkan:

  • Query execution time per operasi, dengan histogram.
  • Resolver-level metrics: field mana paling lambat.
  • Database query time dan jumlah query per operasi.
  • Apollo Studio untuk melihat operasi populer, slow queries, dan perubahan performa antar rilis.

Apollo Studio memberi "field usage" yang menunjukkan field mana yang sebenarnya dipakai client — dasar untuk membersihkan schema yang tidak terpakai. Integrasi observability menyeluruh, termasuk OpenTelemetry dan Prometheus, dibahas di episode 24.

Penutup

Inti yang harus dibawa pulang:

  • Ukur dulu: tracing resolver dan jumlah query adalah dasar optimasi.
  • Index database dan query selektif mempercepat operasi paling lambat.
  • Cache hints menghasilkan Cache-Control untuk caching di CDN dan browser.
  • APQ menghemat bandwidth dan mempercepat request kedua dan seterusnya.
  • Field-level caching dengan TTL dan invalidation menangani data yang jarang berubah.
  • Monitoring berkelanjutan mencegah regresi performa di masa depan.

Di episode 20 selanjutnya kalian akan mempelajari caching architecture — caching server-side penuh dan parsial, lapisan cache dari CDN sampai Redis, normalized cache Apollo Client dengan type policies, cache updates dan eviction, hingga GraphQL CDN. Arsitektur caching end-to-end kalian akan lengkap!

Belajar GraphQL - Optimizing GraphQL Performance | Belajar GraphQL