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.

Việc query SELECT * có cột BLOB (Binary Large Object) trở nên nặng n bởi vì dữ liệu BLOB, dù không phải hình ảnh, vẫn là dữ liệu nhị phân lớn (file, tài liệu, video...) chiếm nhiều không gian và yêu cầu nhiều băng thông/bộ nhớ khi truyền tải, gây quá tải cho mạng, database và ứng dụng, làm chậm toàn bộ hệ thống do phải đọc và xử lý lượng dữ liệu khổng lồ này thay vì chỉ lấy metadata. 

Nguyên nhân chính:

  • Kích thước dữ liệu lớn: BLOB lưu trữ file lớn (PDF, Word, video, audio), ngay cả khi bạn không xem/dùng, việc SELECT * vẫn cố gắng lấy toàn bộ nội dung file đó, rất tốn tài nguyên.
  • I/O đĩa (Disk I/O) cao: Database phải đọc một lượng lớn dữ liệu từ ổ đĩa, tạo gánh nặng lên hệ thống lưu trữ.
  • Băng thông mạng (Network Bandwidth) cạn kiệt: Dữ liệu lớn phải truyền qua mạng từ server database đến ứng dụng, làm chậm quá trình truy xuất.
  • Bộ nhớ (Memory) bị chiếm dụng: Ứng dụng và database cần nhiều RAM để xử lý dữ liệu BLOB. 

Giải pháp:

  1. Tránh SELECT *: Chỉ chọn các cột cần thiết. Nếu cần BLOB, chỉ lấy cột đó khi thực sự cần dùng (ví dụ: khi người dùng click vào tải file).
  2. Sử dụng TOP N hoặc phân trang (Pagination): Lấy từng phần nhỏ dữ liệu hoặc giới hạn số lượng record trả về ban đầu.
  3. Lưu trữ BLOB hiệu quả:
    • File System hoặc Cloud Storage (S3, Azure Blob Storage): Lưu file ngoài database, chỉ lưu đường dẫn (path) trong DB. Database nhẹ hơn, query nhanh hơn, chỉ truy cập file khi cần.
    • Tách riêng: Tách các cột BLOB thành bảng riêng biệt (linked table).
  4. Tối ưu hóa truy vấn: Sử dụng Index phù hợp (cho các cột khác), nhưng index không hiệu quả trực tiếp trên cột BLOB.
  5. Sử dụng OFFSET FETCH hoặc ROW_NUMBER(): Phân trang dữ liệu hiệu quả hơn.
  6. Kiểm tra cấu hình Server: Đảm bảo RAM, Disk I/O, Network đủ mạnh.

Ví dụ thay đổi Query (SQL):
Thay vì: SELECT * FROM Documents;
Hãy dùng: SELECT DocID, DocName, DocType FROM Documents; (Chỉ lấy metadata)

Khi cần file:
SELECT DocContent FROM Documents WHERE DocID = 123; (Chỉ lấy cột BLOB khi cần)