Optimasi Query Database buat SIMRS yang Mulai Lemot

Optimasi Query Database buat SIMRS yang Mulai Lemot

Sobat IT RS, pasti pernah ngalamin SIMRS yang tadinya ngebut, makin lama makin kaya bajaj ngetem. User mulai protes: “Pak, data pasien loading-nya lama banget!” Padahal server belum tua-tua amat, RAM cukup, storage SSD. Usut punya usut, ternyata biang keladi sering dari database yang mulai ngos-ngosan, query makin berat, index berantakan, atau malah belum diapa-apain dari awal. Nah, kali ini kita bedah bareng cara optimasi query SIMRS, fokus ke indexing di MySQL & PostgreSQL. Pengalaman lapangan: bener-bener ngaruh, kadang lebih dahsyat daripada upgrade server. Gaskeun!

Penyebab Query SIMRS Makin Lemot

  • Data numpuk: Tabel pasien, kunjungan, billing, tiap tahun tambah puluhan-ratus ribu row.
  • Query asal-asalan: SELECT * from table, filter ngaco, join ngawur.
  • Index ga keurus: Dari awal install SIMRS, index default doang. Tambah data, index tetep.
  • Tabel bengkak: Satu tabel multi-purpose, semua di-gabung, relasi ga jelas.
  • Maintenance ga rutin: Vacuum, analyze, optimize sekadarnya (atau lupa).

Contoh Kasus: Tabel Kunjungan Pasien

Sobat pasti familiar tabel sejenis ini:

CREATE TABLE kunjungan (
  id_kunjungan INT PRIMARY KEY,
  no_rm VARCHAR(15),
  tgl_kunjungan DATE,
  kode_poli VARCHAR(10),
  dokter VARCHAR(50),
  jenis_kunjungan VARCHAR(20),
  status_bayar VARCHAR(10),
  created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

Data tambah terus, user sering cari transaksi 3-12 bulan mundur, filter per-poli, dokter, status bayar, tanggal range. Query lama-lama makin berat, kadang timeout. Gimana cara ngatasin?

Cek Query Lambat: Tools & Basic Monitoring

MySQL: Slow Query Log

  • Edit my.cnf atau my.ini:
[mysqld]
slow_query_log = 1
slow_query_log_file = /var/log/mysql/slow.log
long_query_time = 1
  • Restart MySQL.
  • Cek isi log:
tail -n 50 /var/log/mysql/slow.log

PostgreSQL: Logging Statements

  • Edit postgresql.conf:
log_min_duration_statement = 1000  # log query >1 detik
log_directory = 'log'
  • Reload PostgreSQL.
  • Cek log:
tail -n 50 /var/lib/pgsql/data/log/postgresql-TANGGAL.log

EXPLAIN: Lihat Cara DB Jalanin Query

Ambil satu query yang sering dikeluhkan user. Misal:

SELECT * FROM kunjungan
WHERE kode_poli = 'INT'
AND tgl_kunjungan BETWEEN '2023-01-01' AND '2023-12-31'
ORDER BY tgl_kunjungan DESC
LIMIT 50;

Cek dengan EXPLAIN:

EXPLAIN SELECT * FROM kunjungan ...;

Kalo muncul “Seq Scan” di PostgreSQL atau “ALL” di MySQL, tanda query scan semua row (full scan) — biang lemot.

Basic Indexing: Dasar Teori (Singkat, Gak Teori Doang)

  • Index di DB = buku telepon. Tanpa index, DB cari satu-satu dari halaman pertama sampai ketemu.
  • Index bikin DB bisa “lompat” langsung ke baris yang sesuai kondisi WHERE/ORDER BY/SELECT.
  • Kolom yang sering dipake buat filter, join, atau sort, itu kandidat index.

Jenis Index Penting di SIMRS

  • Single column index: Buat kolom yang sering buat filter, misal no_rm, kode_poli, tgl_kunjungan.
  • Composite (multi-column) index: Buat query yang WHERE/ORDER BY >1 kolom.
  • Unique index: Jaga biar data ga dobel, misal no_rm unik, id_kunjungan.

Praktik Indexing di MySQL

Cek Index yang Sudah Ada

SHOW INDEX FROM kunjungan;

Bikin Index Single Column

Misal user sering filter berdasarkan kode_poli:

CREATE INDEX idx_kunjungan_kode_poli ON kunjungan(kode_poli);

Bikin Composite Index

  • Perhatikan urutan kolom: Index (kode_poli, tgl_kunjungan) beda dengan (tgl_kunjungan, kode_poli).
  • Ideal buat query filter/urutan banyak kolom.
CREATE INDEX idx_kunj_kodepoli_tgl ON kunjungan(kode_poli, tgl_kunjungan DESC);

Index ini kepake buat query:

SELECT * FROM kunjungan
WHERE kode_poli = 'IGD'
AND tgl_kunjungan BETWEEN '2023-01-01' AND '2023-12-31'
ORDER BY tgl_kunjungan DESC
LIMIT 50;

Drop Index yang Gak Perlu

Index kebanyakan bikin insert/update tambah berat, space abis. Buang index tua/mubazir:

DROP INDEX idx_lama ON kunjungan;

MySQL: Nama index tampil di SHOW INDEX, bukan nama kolom!

Optimasi Query Setelah Index

Cek ulang query pake EXPLAIN:

EXPLAIN SELECT ...;
  • Pastikan kolom key sesuai index baru, rows jauh lebih sedikit dari total row.

Praktik Indexing di PostgreSQL

Cek Index yang Sudah Ada

\di kunjungan*

Bikin Index Single Column

CREATE INDEX idx_kunjungan_kodepoli ON kunjungan (kode_poli);

Bikin Composite Index

CREATE INDEX idx_kunjungan_kodepoli_tgl ON kunjungan (kode_poli, tgl_kunjungan DESC);

Postgres bisa pake btree (default), gin, gist — kalo buat WHERE/ORDER BY standar, cukup btree.

Drop Index yang Ga Dipake

DROP INDEX IF EXISTS idx_kunjungan_kodepoli_lama;

Tips: Partial Index, Buat yang Sering Filter Nilai Tertentu

Misal status_bayar = ‘LUNAS’ sering dicari:

CREATE INDEX idx_kunj_lunas ON kunjungan (kode_poli, tgl_kunjungan)
WHERE status_bayar = 'LUNAS';

Reindex Manual Kalau Index Udah Fragmented

REINDEX TABLE kunjungan;

Studi Kasus: Percepatan Query Laporan Kunjungan

Sebelum Index

Query:

SELECT kode_poli, COUNT(*) FROM kunjungan
WHERE tgl_kunjungan BETWEEN '2023-07-01' AND '2023-07-31'
GROUP BY kode_poli;

Lama loading: 12 detik (baris >500.000, full scan, grouping manual).

Setelah Index di tgl_kunjungan, kode_poli

CREATE INDEX idx_kunj_tglpoli ON kunjungan (tgl_kunjungan, kode_poli);

Ulang query. Loading: