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:
PETIRS