Bài 4: Tối ưu câu lệnh SELECT

Câu lệnh SELECT là một trong những câu lệnh được sử dụng phổ biến nhất trong SQL, và việc tối ưu hóa nó có thể mang lại hiệu suất đáng kể cho hệ thống cơ sở dữ liệu. Bài viết này sẽ đi sâu vào các kỹ thuật tối ưu hóa câu lệnh SELECT, bao gồm cách viết truy vấn hiệu quả, tối ưu hóa JOIN, và sử dụng điều kiện WHERE một cách thông minh.


4.1. Chỉ lấy dữ liệu cần thiết

Một trong những nguyên tắc cơ bản nhất khi viết truy vấn SELECT là chỉ lấy những dữ liệu thực sự cần thiết. Điều này không chỉ giúp giảm tải cho hệ thống mà còn cải thiện thời gian thực thi của truy vấn.

4.1.1. Sử dụng SELECT cụ thể thay vì SELECT *
  • Vấn đề: Khi sử dụng SELECT *, database engine sẽ trả về tất cả các cột trong bảng, ngay cả những cột không cần thiết. Điều này làm tăng lượng dữ liệu truyền tải và tiêu tốn tài nguyên.

  • Giải pháp: Chỉ chọn những cột cần thiết trong truy vấn.

    • Ví dụ không tối ưu: SELECT * FROM employees;

    • Ví dụ tối ưu: SELECT employee_id, first_name, last_name FROM employees;

4.1.2. Giới hạn số lượng bản ghi với LIMIT hoặc TOP
  • Vấn đề: Khi truy vấn trả về một số lượng lớn bản ghi, nó có thể làm chậm hệ thống và tiêu tốn bộ nhớ.

  • Giải pháp: Sử dụng LIMIT (trong MySQL, PostgreSQL) hoặc TOP (trong SQL Server) để giới hạn số lượng bản ghi trả về.

    • Ví dụ không tối ưu: SELECT * FROM employees;

    • Ví dụ tối ưu: SELECT * FROM employees LIMIT 100; (MySQL, PostgreSQL) hoặc SELECT TOP 100 * FROM employees; (SQL Server)


4.2. Tối ưu JOIN

JOIN là một phép toán phổ biến trong SQL, nhưng nếu không được sử dụng đúng cách, nó có thể làm chậm truy vấn đáng kể. Dưới đây là một số kỹ thuật tối ưu hóa JOIN.

4.2.1. Sử dụng đúng loại JOIN
  • INNER JOIN: Sử dụng khi bạn chỉ cần các bản ghi có sự khớp nhau giữa hai bảng.

    • Ví dụ: SELECT e.employee_id, e.first_name, d.department_name FROM employees e INNER JOIN departments d ON e.department_id = d.department_id;
  • LEFT JOIN (hoặc RIGHT JOIN): Sử dụng khi bạn cần tất cả các bản ghi từ một bảng và các bản ghi khớp từ bảng còn lại.

    • Ví dụ: SELECT e.employee_id, e.first_name, d.department_name FROM employees e LEFT JOIN departments d ON e.department_id = d.department_id;
  • FULL OUTER JOIN: Sử dụng khi bạn cần tất cả các bản ghi từ cả hai bảng, kể cả những bản ghi không khớp.

    • Ví dụ: SELECT e.employee_id, e.first_name, d.department_name FROM employees e FULL OUTER JOIN departments d ON e.department_id = d.department_id;
4.2.2. Tránh JOIN quá nhiều bảng
  • Vấn đề: JOIN quá nhiều bảng có thể làm tăng độ phức tạp của truy vấn và dẫn đến hiệu suất kém.

  • Giải pháp:

    • Chỉ JOIN những bảng cần thiết.

    • Sử dụng subquery hoặc Common Table Expressions (CTE) để chia nhỏ truy vấn phức tạp thành các phần đơn giản hơn.

    • Ví dụ không tối ưu: SELECT * FROM orders o JOIN customers c ON o.customer_id = c.customer_id JOIN products p ON o.product_id = p.product_id JOIN suppliers s ON p.supplier_id = s.supplier_id;

    • Ví dụ tối ưu: Chia nhỏ truy vấn thành các phần nhỏ hơn hoặc sử dụng CTE.


4.3. Sử dụng WHERE hiệu quả

Điều kiện WHERE là một phần quan trọng của câu lệnh SELECT, và việc sử dụng nó một cách hiệu quả có thể cải thiện đáng kể hiệu suất của truy vấn.

4.3.1. Đặt điều kiện WHERE hợp lý
  • Vấn đề: Điều kiện WHERE không hợp lý có thể dẫn đến việc quét toàn bộ bảng (table scan) thay vì sử dụng index.

  • Giải pháp: Đảm bảo rằng điều kiện WHERE được viết một cách hợp lý và sử dụng các cột có index.

    • Ví dụ không tối ưu: SELECT * FROM employees WHERE YEAR(hire_date) = 2023; (sử dụng hàm trên cột hire_date làm mất hiệu quả của index)

    • Ví dụ tối ưu: SELECT * FROM employees WHERE hire_date BETWEEN '2023-01-01' AND '2023-12-31';

4.3.2. Tránh sử dụng hàm trong WHERE
  • Vấn đề: Sử dụng hàm trong điều kiện WHERE có thể làm mất hiệu quả của index.

  • Giải pháp: Tránh sử dụng các hàm như UPPER(), LOWER(), YEAR(), MONTH(), v.v. trong điều kiện WHERE. Thay vào đó, hãy sử dụng các điều kiện trực tiếp trên cột.

    • Ví dụ không tối ưu: SELECT * FROM employees WHERE UPPER(last_name) = 'SMITH';

    • Ví dụ tối ưu: SELECT * FROM employees WHERE last_name = 'Smith'; (giả sử dữ liệu đã được chuẩn hóa)


Kết luận

Tối ưu hóa câu lệnh SELECT là một quá trình quan trọng để cải thiện hiệu suất của hệ thống cơ sở dữ liệu. Bằng cách chỉ lấy những dữ liệu cần thiết, sử dụng đúng loại JOIN, và viết điều kiện WHERE một cách hiệu quả, bạn có thể giảm đáng kể thời gian thực thi của truy vấn và tiết kiệm tài nguyên hệ thống. Trong các bài tiếp theo, chúng ta sẽ đi sâu vào các kỹ thuật tối ưu hóa khác, chẳng hạn như tối ưu câu lệnh INSERT, UPDATE, và DELETE.


Từ vựng chuyên môn (Glossary)

  • SELECT: Câu lệnh chọn dữ liệu.

  • JOIN: Phép kết hợp dữ liệu từ nhiều bảng.

  • INNER JOIN: Kết hợp các bản ghi có sự khớp nhau giữa hai bảng.

  • LEFT JOIN: Kết hợp tất cả các bản ghi từ bảng bên trái và các bản ghi khớp từ bảng bên phải.

  • RIGHT JOIN: Kết hợp tất cả các bản ghi từ bảng bên phải và các bản ghi khớp từ bảng bên trái.

  • FULL OUTER JOIN: Kết hợp tất cả các bản ghi từ cả hai bảng, kể cả những bản ghi không khớp.

  • WHERE: Điều kiện lọc dữ liệu.

  • LIMIT: Giới hạn số lượng bản ghi trả về (MySQL, PostgreSQL).

  • TOP: Giới hạn số lượng bản ghi trả về (SQL Server).

  • Table Scan: Quét toàn bộ bảng.

  • Index Scan: Quét chỉ mục.