6 câu hỏi về tối ưu MySQL Performance Optimization

1. Tại sao query này chậm? Làm sao phân tích và tối ưu?

Trả lời:
Tôi bắt đầu bằng việc chạy EXPLAIN để xem MySQL chọn index nào, kiểu truy vấn (type = ALL, ref, index…), và số dòng ước tính (rows).
Nếu thấy type=ALL → full table scan → cần thêm hoặc tối ưu index.
Sau đó kiểm tra:

  • WHEREORDER BYGROUP BY có dùng cột chưa được index.
  • Query có LIKE '%abc' → không dùng index.
  • Có JOIN bảng lớn không dùng khóa ngoài → xem lại quan hệ hoặc thêm index.
    Cuối cùng, tôi dùng SHOW PROFILES hoặc slow query log để xác định bottleneck CPU/I/O.

Kết luận: tối ưu bằng index đúng cột, tránh hàm trên cột (LOWER(col)), và refactor query logic.

2. Khi nào bạn dùng Composite Index?

Trả lời:
Khi query lọc theo nhiều cột có thứ tự cố định.
Ví dụ:

SELECT * FROM orders WHERE user_id = ? AND created_at > ?

→ tạo index (user_id, created_at) giúp MySQL chỉ quét phạm vi cần.
Tôi nhớ quy tắc “Leftmost Prefix”: MySQL chỉ dùng index từ trái sang phải, nên thứ tự cột trong index phải trùng với pattern query phổ biến.
Cũng lưu ý: không nên tạo index trùng lặp ((user_id) và (user_id, created_at)).

3. EXPLAIN cho thấy “Using filesort” — nghĩa là gì và xử lý ra sao?

Trả lời:
Using filesort nghĩa là MySQL phải tự sắp xếp dữ liệu trong RAM hoặc disk (thay vì đọc theo index).
Tôi sẽ kiểm tra ORDER BY và WHERE có thể dùng cùng một index không.
Nếu query:

SELECT * FROM orders WHERE user_id = ? ORDER BY created_at DESC

→ tạo index (user_id, created_at DESC) sẽ tránh “Using filesort”.
Ngoài ra, giảm số lượng cột select (chỉ lấy cần thiết) cũng giảm tải sorting.

4. Khi nào nên dùng EXISTS thay vì JOIN hoặc IN?

Trả lời:

  • EXISTS tốt hơn IN khi bảng con lớn vì nó dừng kiểm tra ngay khi tìm thấy match đầu tiên.
  • JOIN hữu ích khi cần lấy dữ liệu từ nhiều bảng, nhưng có thể sinh duplicate hoặc scan lớn.
    Ví dụ:
SELECT * FROM users u WHERE EXISTS (
  SELECT 1 FROM orders o WHERE o.user_id = u.id
)

→ hiệu quả hơn WHERE u.id IN (SELECT user_id FROM orders) nếu orders có nhiều dòng.

5. Làm thế nào để phát hiện và xử lý query chậm trong production Laravel?

Trả lời:

  • Bật slow_query_log trên MySQL, đặt threshold (vd: 0.5s).
  • Trong Laravel, dùng DB::listen() để log query > X ms.
  • Dùng công cụ profiling như Laravel TelescopeClockwork hoặc Blackfire.
  • Khi xác định query chậm, tôi chạy EXPLAIN, thêm index, refactor logic hoặc caching (Redis).
  • Nếu query do ORM sinh ra, tôi kiểm tra N+1 queries, thêm with() để eager load.

6. Giải thích cách tối ưu MySQL cho hệ thống có lượng ghi (write) cao.

Trả lời:

  • Tối ưu InnoDB configinnodb_flush_log_at_trx_commit=2innodb_buffer_pool_size chiếm ~70% RAM.
  • Giảm khóa (locking): chia transaction nhỏ, tránh update hàng loạt.
  • Sharding hoặc phân vùng (partitioning) dữ liệu lớn.
  • Batch insert/update thay vì từng dòng.
  • Dùng queue (Kafka) để xử lý async thay vì ghi đồng bộ ngay.
  • Index tối thiểu cần thiết: vì mỗi index thêm chi phí ghi.