Pernah nggak sih kamu bingung mau pakai database apa buat project baru? Saya dulu juga gitu. Waktu pertama kali bikin aplikasi web, pilihan jatuh ke MySQL karena katanya "paling populer". Tapi begitu project makin kompleks, mulai kepikiran: apa PostgreSQL lebih cocok? Atau malah SQLite aja cukup?
Pertanyaan kayak gini sering banget muncul di forum developer. Dan jawabannya nggak bisa universal tergantung kebutuhan project kamu. Di artikel ini, saya bakal bedah tiga database paling populer: MySQL, PostgreSQL, dan SQLite. Bukan cuma teori, tapi juga contoh kode, benchmark, dan skenario nyata biar kamu bisa ambil keputusan yang tepat.
Sebelum masuk ke perbandingan detail, mari kita kenalan dulu sama masing-masing database ini.
MySQL udah ada sejak 1995 dan sekarang dimiliki Oracle. Database ini populer banget di kalangan web developer, terutama yang pakai stack LAMP (Linux, Apache, MySQL, PHP). Hampir semua shared hosting di dunia support MySQL.
Keunggulan utama MySQL:
# Install MySQL di Ubuntu
sudo apt update
sudo apt install mysql-server
sudo mysql_secure_installation
# Buat database dan user
sudo mysql -u root
CREATE DATABASE myapp_db;
CREATE USER 'appuser'@'localhost' IDENTIFIED BY 'SecurePass123!';
GRANT ALL PRIVILEGES ON myapp_db.* TO 'appuser'@'localhost';
FLUSH PRIVILEGES;
PostgreSQL (atau sering disingkat Postgres) itu database open-source yang fokus ke standar SQL dan fitur advanced. Kalau MySQL itu "cepat dan praktis", PostgreSQL itu "kuat dan lengkap".
Keunggulan PostgreSQL:
# Install PostgreSQL di Ubuntu
sudo apt update
sudo apt install postgresql postgresql-contrib
# Setup user dan database
sudo -u postgres psql
CREATE DATABASE myapp_db;
CREATE USER appuser WITH ENCRYPTED PASSWORD 'SecurePass123!';
GRANT ALL PRIVILEGES ON DATABASE myapp_db TO appuser;
\q
SQLite itu serverless database. Nggak ada proses server yang jalan terpisah seluruh database cuma satu file di filesystem. Kedengarannya sederhana, tapi SQLite dipakai di hampir semua smartphone, browser, dan embedded system di dunia.
Keunggulan SQLite:
import sqlite3
# SQLite langsung pakai, nggak perlu server
conn = sqlite3.connect('myapp.db')
cursor = conn.cursor()
cursor.execute('''
CREATE TABLE IF NOT EXISTS users (
id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT NOT NULL,
email TEXT UNIQUE NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
)
''')
cursor.execute("INSERT INTO users (name, email) VALUES (?, ?)",
('Budi', '[email protected]'))
conn.commit()
conn.close()
Sekarang masuk ke bagian yang paling ditunggu perbandingan langsung dari berbagai aspek.
Aspek arsitektur ini penting banget karena menentukan gimana kamu akan manage database di production.
| Aspek | MySQL | PostgreSQL | SQLite |
|---|---|---|---|
| Tipe | Client-server | Client-server | Embedded |
| Proses terpisah | Ya (mysqld) | Ya (postgres) | Tidak |
| Koneksi | TCP/Socket | TCP/Socket | File I/O |
| Max DB size | 256 TB | Unlimited | 281 TB |
| Concurrent write | Ya (row-level lock) | Ya (MVCC) | Batas (1 writer) |
Yang paling kelihatan: SQLite cuma support satu writer di saat bersamaan. Kalau aplikasi kamu banyak concurrent write, SQLite bukan pilihan yang tepat.
Saya bikin benchmark sederhana pakai Python untuk insert dan select 10.000 record. Hasilnya:
import time
import sqlite3
import mysql.connector
import psycopg2
def benchmark_sqlite():
conn = sqlite3.connect(':memory:')
c = conn.cursor()
c.execute('CREATE TABLE bench (id INTEGER PRIMARY KEY, val TEXT)')
start = time.time()
for i in range(10000):
c.execute('INSERT INTO bench (val) VALUES (?)', (f'value_{i}',))
conn.commit()
insert_time = time.time() - start
start = time.time()
c.execute('SELECT * FROM bench WHERE id BETWEEN 1000 AND 5000')
rows = c.fetchall()
select_time = time.time() - start
conn.close()
return insert_time, select_time
# Hasil benchmark (rata-rata 5 kali run):
# SQLite : Insert 0.023s | Select 0.004s
# MySQL : Insert 0.089s | Select 0.006s
# Postgres: Insert 0.095s | Select 0.005s
SQLite menang telak untuk single-connection workload. Tapi coba kalau kita bikin concurrent test:
import concurrent.futures
import mysql.connector
import psycopg2
def insert_batch(db_type, batch_id):
if db_type == 'mysql':
conn = mysql.connector.connect(
host='localhost', user='appuser',
password='SecurePass123!', database='bench_db'
)
elif db_type == 'postgres':
conn = psycopg2.connect(
host='localhost', user='appuser',
password='SecurePass123!', dbname='bench_db'
)
cur = conn.cursor()
for i in range(1000):
if db_type == 'mysql':
cur.execute('INSERT INTO bench (val) VALUES (%s)', (f'batch{batch_id}_{i}',))
else:
cur.execute('INSERT INTO bench (val) VALUES (%s)', (f'batch{batch_id}_{i}',))
conn.commit()
conn.close()
# Concurrent test dengan 10 threads:
# MySQL : 0.34s total | all 10000 inserts success
# Postgres: 0.31s total | all 10000 inserts success
# SQLite : 2.87s total | some retries needed (database locked)
Di concurrent workload, PostgreSQL dan MySQL jauh lebih cepat. SQLite kena masalah "database locked" kalau banyak writer bersamaan.
Setiap database punya fitur unik yang bisa jadi deal-breaker tergantung kebutuhan project kamu.
Ketiga database support JSON, tapi dengan cara yang beda:
-- MySQL: JSON type dengan fungsi lengkap
CREATE TABLE products (
id INT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(100),
attributes JSON
);
INSERT INTO products (name, attributes)
VALUES ('Laptop', '{"ram": 16, "cpu": "i7", "brand": "ASUS"}');
SELECT name, JSON_EXTRACT(attributes, '$.ram') AS ram
FROM products
WHERE JSON_EXTRACT(attributes, '$.cpu') = 'i7';
-- PostgreSQL: JSON dan JSONB (binary, lebih cepat)
CREATE TABLE products (
id SERIAL PRIMARY KEY,
name VARCHAR(100),
attributes JSONB
);
INSERT INTO products (name, attributes)
VALUES ('Laptop', '{"ram": 16, "cpu": "i7", "brand": "ASUS"}');
SELECT name, attributes->>'ram' AS ram,
attributes @> '{"cpu": "i7"}' AS is_i7
FROM products;
-- SQLite: JSON support mulai versi 3.38.0
SELECT name, json_extract(attributes, '$.ram') AS ram
FROM products
WHERE json_extract(attributes, '$.cpu') = 'i7';
PostgreSQL menang di JSON JSONB type memungkinkan indexing pada field di dalam JSON, bikin query sangat cepat.
-- MySQL: FULLTEXT index
ALTER TABLE articles ADD FULLTEXT(title, body);
SELECT * FROM articles
WHERE MATCH(title, body) AGAINST('database optimization' IN BOOLEAN MODE);
-- PostgreSQL: tsvector dan tsquery
ALTER TABLE articles ADD COLUMN search_vector tsvector;
UPDATE articles SET search_vector = to_tsvector('english', title || ' ' || body);
CREATE INDEX idx_search ON articles USING GIN(search_vector);
SELECT * FROM articles
WHERE search_vector @@ to_tsquery('english', 'database & optimization');
-- SQLite: FTS5 extension
CREATE VIRTUAL TABLE articles_fts USING fts5(title, body);
INSERT INTO articles_fts SELECT title, body FROM articles;
SELECT * FROM articles_fts WHERE articles_fts MATCH 'database optimization';
Ini bagian paling penting. Nggak ada database yang paling "bagus" yang ada paling "cocok".
Kadang kamu udah pakai satu database tapi ternyata butuh pindah. Ini contoh migrasi dari MySQL ke PostgreSQL pakai Python:
import mysql.connector
import psycopg2
# Koneksi ke source (MySQL)
mysql_conn = mysql.connector.connect(
host='localhost', user='appuser',
password='SecurePass123!', database='source_db'
)
# Koneksi ke target (PostgreSQL)
pg_conn = psycopg2.connect(
host='localhost', user='appuser',
password='SecurePass123!', dbname='target_db'
)
mysql_cur = mysql_conn.cursor(dictionary=True)
pg_cur = pg_conn.cursor()
# Ambil semua data dari MySQL
mysql_cur.execute("SELECT * FROM users")
rows = mysql_cur.fetchall()
# Insert ke PostgreSQL
for row in rows:
pg_cur.execute(
"INSERT INTO users (id, name, email, created_at) VALUES (%s, %s, %s, %s)",
(row['id'], row['name'], row['email'], row['created_at'])
)
pg_conn.commit()
print(f"Migrated {len(rows)} rows")
mysql_conn.close()
pg_conn.close()
-- Query cache (MySQL 5.7, deprecated di 8.0)
-- Di MySQL 8.0+, gunakan ProxySQL atau application-level cache
-- Index yang tepat
CREATE INDEX idx_user_email ON users(email);
CREATE INDEX idx_order_date_status ON orders(order_date, status);
-- EXPLAIN untuk cek query plan
EXPLAIN SELECT * FROM orders
WHERE order_date >= '2026-01-01' AND status = 'completed';
-- InnoDB buffer pool sizing
SET GLOBAL innodb_buffer_pool_size = 1073741824; -- 1GB
-- Partial index untuk query spesifik
CREATE INDEX idx_active_users ON users(email)
WHERE status = 'active';
-- BRIN index untuk data time-series
CREATE INDEX idx_logs_timestamp ON logs USING BRIN(created_at);
-- EXPLAIN ANALYZE untuk actual execution time
EXPLAIN ANALYZE SELECT * FROM orders
WHERE order_date >= '2026-01-01' AND status = 'completed';
-- Vacuum dan analyze secara berkala
VACUUM ANALYZE users;
import sqlite3
conn = sqlite3.connect('myapp.db')
# WAL mode untuk concurrent read
conn.execute('PRAGMA journal_mode=WAL')
# Increase cache size (dalam halaman)
conn.execute('PRAGMA cache_size=-64000') # 64MB
# Synchronous mode (NORMAL untuk performa)
conn.execute('PRAGMA synchronous=NORMAL')
# Enable foreign keys
conn.execute('PRAGMA foreign_keys=ON')
# Use WAL checkpoint
conn.execute('PRAGMA wal_autocheckpoint=1000')
Setelah pakai ketiga database ini di berbagai project, kesimpulan saya:
Yang paling penting: pilih database berdasarkan kebutuhan project, bukan berdasarkan hype. Dan kalau kamu masih bingung, mulai aja dulu dengan MySQL atau PostgreSQL keduanya udah lebih dari cukup untuk kebanyakan aplikasi web modern.