Tất cả bài viết

SQL vs NoSQL — chọn sai là refactor cả đời

NoSQL không phải phiên bản mới hơn của SQL. Chúng giải quyết vấn đề khác nhau. Chọn dựa trên access pattern, consistency requirement, và team capability — không phải trend.

databaseSQLNoSQLtrade-off

Mày nghe tin NoSQL “scale tốt hơn”, “flexible hơn”, “không cần schema”. Cân nhắc dùng MongoDB cho HMS thay vì MySQL.

Rồi 6 tháng sau, mày phát hiện:

Muốn refactor lại? Đã quá muộn. Cả terabyte data.

Chọn database type là decision lâu dài. Mày cần hiểu khi nào nên SQL, khi nào nên NoSQL.


SQL — ACID, Schema, Relational

Đặc điểm:

Khi dùng SQL:

Khi tránh SQL:


NoSQL — Flexible, Scalable, Eventually Consistent

Đặc điểm:

Khi dùng NoSQL:

Khi tránh NoSQL:


Ví dụ thực tế — HMS

Bảng nào SQL, bảng nào NoSQL?

SQL (core business logic):

NoSQL (supporting data):

Decision: MySQL cho core, Redis/MongoDB cho auxiliary. Không recommend pure NoSQL cho HMS.


SQL query mà NoSQL khó làm

-- Find appointments booking more than 5 patients with status CONFIRMED
-- Group by doctor, count appointments
SELECT 
    d.name,
    COUNT(a.id) as appointment_count,
    SUM(a.fee) as revenue
FROM appointment a
JOIN doctor d ON a.doctor_id = d.id
WHERE a.status = 'CONFIRMED'
    AND a.appointment_time >= DATE_SUB(NOW(), INTERVAL 30 DAY)
GROUP BY d.id, d.name
HAVING COUNT(a.id) >= 5
ORDER BY revenue DESC;

Di MongoDB:

db.appointments.aggregate([
    { $match: { status: 'CONFIRMED', appointment_time: { $gte: new Date(...) } } },
    { $lookup: { 
        from: 'doctors',
        localField: 'doctor_id',
        foreignField: 'id',
        as: 'doctor'
    }},
    { $unwind: '$doctor' },
    { $group: { 
        _id: '$doctor.id',
        name: { $first: '$doctor.name' },
        appointment_count: { $sum: 1 },
        revenue: { $sum: '$fee' }
    }},
    { $match: { appointment_count: { $gte: 5 } } },
    { $sort: { revenue: -1 } }
]);

MongoDB cũng làm được, nhưng cú pháp kỳ quặc hơn, performance kém SQL (không có query optimizer).


SQL vs NoSQL — Performance myth

Myth: NoSQL faster.

Truth: Depend on pattern.

HMS bạn — read pattern: “get appointments của doctor này ngày này” — SQL optimize điều này. NoSQL không.


Cách pick: chỉ dùng NoSQL nếu SQL fail

Start SQL. Sau đó:

  1. Monitor slow queries — nếu query chậm (10+ sec), optimize index/query trước
  2. Monitor write throughput — nếu write lag behind (queue building), xem tại sao (deadlock? constraint check?)
  3. Monitor storage — nếu storage overflow, denormalize hoặc archive cũ
  4. Chỉ switch NoSQL nếu SQL fundamentally không fit

Hầu hết project, SQL đủ. Khi nào SQL fail thực sự hiếm (tí xíu %).


Hybrid approach — SQL + NoSQL

Thực tế production:

MySQL (core business data):
  - Appointment
  - Doctor
  - Patient
  - Payment

Redis (cache + session):
  - Booking slot availability
  - User session
  - Rate limit counter

MongoDB (audit log + analytics):
  - Activity log
  - Error log
  - Analytics event

Không pure SQL, không pure NoSQL. Polyglot persistence — dùng database đúng tool cho đúng job.

Ví dụ: Appointment booking.

@Transactional
public void bookAppointment(UUID scheduleId, UUID patientId) {
    // SQL: atomic transaction
    DoctorSchedule schedule = scheduleRepo.findById(scheduleId).lock();
    schedule.decrement();
    
    Appointment app = appointmentRepo.save(new Appointment(...));
    
    // Redis: cache invalidation
    redisCache.invalidate("schedule:" + scheduleId);
    
    // MongoDB: audit log
    mongoAuditLog.insert(new BookingEvent(app.getId(), patientId));
}

Takeaway

SQL là default. NoSQL chỉ khi SQL proven not fit (prove bằng metrics: slow query, write bottleneck). HMS của mày — SQL + Redis là đủ năm tới.


Bài tiếp theo: Soft Delete — đơn giản hơn mày nghĩ, và phức tạp hơn mày tưởng