Mở đầu
Trong thế giới dữ liệu, tốc độ truy vấn thường quyết định trải nghiệm người dùng và hiệu quả kinh doanh. Một câu lệnh SQL được viết tốt có thể trả về kết quả trong vài mili giây, trong khi cùng một logic được thực thi kém có thể mất vài giây hoặc hơn. Đó là lý do tối ưu hiệu năng truy vấn trong MySQL không chỉ là kỹ năng của DBA mà còn là mối quan tâm của mọi lập trình viên backend. Bài viết này sẽ đi sâu vào các kỹ thuật, công cụ và thói quen giúp bạn khai thác tối đa sức mạnh của MySQL.
Hiểu rõ vấn đề trước khi tối ưu
Trước khi bắt tay vào tối ưu, cần xác định đúng “điểm nghẽn”. MySQL cung cấp công cụ EXPLAIN để phân tích kế hoạch thực thi truy vấn. Kết quả trả về cho biết MySQL sẽ quét bảng như thế nào, sử dụng index ra sao, và thứ tự join các bảng. Nếu thấy type: ALL (full table scan) hoặc rows quá lớn, đó là dấu hiệu cần xem xét lại.
Ngoài ra, slow query log giúp ghi lại các truy vấn vượt ngưỡng thời gian cho phép. Bật log này trong file cấu hình my.cnf:
slow_query_log = 1
slow_query_log_file = /var/log/mysql-slow.log
long_query_time = 1Tối ưu cấu trúc và index
Index là “vũ khí” mạnh nhất để tăng tốc truy vấn. Tuy nhiên, không phải lúc nào thêm index cũng tốt—nó làm chậm INSERT/UPDATE và tốn disk. Chọn index phù hợp dựa trên thói quen truy vấn:
– Composite index: Khi truy vấn thường xuyên lọc theo nhiều cột, tạo index trên các cột đó theo thứ tự quan trọng. Ví dụ: INDEX idx_name_age (last_name, age).
– Covering index: Index chứa đủ cột để trả lời truy vấn mà không cần đọc dữ liệu gốc. Giúp tốc độ tăng đáng kể.
– Tránh over-indexing: Mỗi index thêm vào làm tăng chi phí ghi. Chỉ index những cột thực sự cần.
Đối với các truy vấn full-text, MySQL cung cấp FULLTEXT index (InnoDB từ 5.6), cho phép tìm kiếm từ khóa hiệu quả hơn LIKE.
Tối ưu câu lệnh SQL
Một câu lệnh được viết khéo có thể loại bỏ hoàn toàn nhu cầu dùng index phức tạp:
– Chọn đúng kiểu JOIN: INNER JOIN nhanh hơn LEFT JOIN khi không cần dữ liệu bên trái. Tránh CROSS JOIN trừ khi thực sự cần.
– Hạn chế dùng OR: OR thường ngăn MySQL dùng index hiệu quả. Thay thế bằng UNION hoặc IN khi có thể.
– Dùng WHERE sớm: Đẩy điều kiện lọc vào WHERE thay vì HAVING để giảm dữ liệu sớm nhất có thể.
– Tránh SELECT *: Liệt kê rõ cột cần lấy, giảm băng thông và I/O.
Ví dụ:
-- Kém
SELECT * FROM users WHERE status = 'active' AND created_at > '2024-01-01';
-- Tốt hơn
SELECT id, name, email FROM users
WHERE status = 'active' AND created_at > '2024-01-01';