Lý do SELECT * có cột BLOB khiến query rất nặng nằm ở 3 tầng khác nhau:


⚙️ 1. Cơ chế lưu trữ và nạp dữ liệu của MySQL

MySQL không biết bạn “chỉ cần metadata, không cần ảnh”, nên khi bạn SELECT *, nó đọc toàn bộ nội dung của cột BLOB từ disk vào RAM, rồi mới gửi sang client.
Dù bạn không dùng tới trường đó, quá trình vẫn xảy ra.

  • Nếu ảnh là vài trăm KB hoặc vài MB → mỗi dòng query sẽ phải load từng ấy dữ liệu.
  • 1.000 dòng × 500KB = 500MB phải truyền qua network MySQL → PHP → webserver.

➡️ Kết quả: query tốn thời gian, RAM và băng thông cực lớn.


🧩 2. Cách MySQL quản lý bộ nhớ tạm (buffer)

Khi MySQL Server xử lý query có BLOB:

  • Nó phải dựng buffer động để chứa cột lớn này trong bộ nhớ.
  • Buffer lớn → tăng memory usage → dễ đụng max_allowed_packet hoặc sort_buffer_size.
  • Nếu server bị ép bộ nhớ, MySQL có thể swap ra disk, khiến query chậm cực kỳ.

🌐 3. Truyền dữ liệu qua network đến client (PHP)

Sau khi MySQL load xong:

  • Dữ liệu BLOB được chuyển nguyên dạng binary qua socket tới PHP.
  • PHP MySQLi/PDO lại phải nhận toàn bộ chuỗi byte, giải mã, lưu vào memory của tiến trình PHP.
  • Nếu bạn query nhiều dòng, bộ nhớ PHP sẽ phình rất nhanhAllowed memory size exhausted.

💡 Kết luận

Tình huốngTác động
SELECT * FROM media_files (có cột BLOB)Nặng, đọc toàn bộ dữ liệu ảnh
SELECT id, file_name FROM media_filesNhẹ, chỉ đọc metadata
SELECT file_data FROM media_files WHERE id = ?Hợp lý, chỉ lấy khi thực sự cần ảnh

✅ Cách khắc phục

  1. Không bao giờ dùng SELECT * trên bảng có BLOB.
    → Luôn chỉ định cột cụ thể.
  2. Nếu bạn hay cần metadata + ảnh → tách ảnh sang bảng riêng: media_meta(id, name, mime_type, size) media_data(id, file_data LONGBLOB)
  3. Giảm kích thước ảnh, nén base64 hoặc WebP trước khi insert.