SQL: WHERE trước hay JOIN trước? Một ít hiểu biết về Cost Optimizer

0 0 0

Người đăng: Nguyễn Đắc Khoa

Theo Viblo Asia

Giới thiệu

Trước đây, khi mình viết một câu SQL query, thỉnh thoảng có người hỏi mình: "WHERE trước hay JOIN trước?" Và sau đó thì mình nhận ra câu hỏi đó rất phổ biến mà nhiều người mới học hoặc thậm chí các lập trình viên có kinh nghiệm vẫn đang nhầm lẫn. Họ cho rằng việc lọc dữ liệu bằng WHERE trước sẽ giảm số lượng bản ghi, từ đó giúp câu query chạy nhanh hơn. Tuy nhiên, liệu điều này có thực sự đúng? Trong bài blog này, chúng ta sẽ khám phá cách hoạt động của SQL, vai trò của Cost Optimizer, và giải đáp chi tiết câu hỏi này.

Câu hỏi: Thứ tự viết query có ảnh hưởng đến hiệu suất?

Trong SQL, thứ tự bạn viết các mệnh đề (SELECT, FROM, JOIN, WHERE, v.v.) tuân theo cú pháp chuẩn. Ví dụ:

SELECT column1, column2
FROM table1
JOIN table2 ON table1.id = table2.id
WHERE column1 = 'value';

Nhiều người nghĩ rằng SQL sẽ thực thi đúng theo thứ tự này: lấy dữ liệu từ table1, thực hiện JOIN với table2, rồi mới áp dụng điều kiện WHERE. Nếu vậy, việc lọc bằng WHERE trước có thể giảm số lượng bản ghi trước khi JOIN, từ đó cải thiện hiệu suất. Nhưng thực tế không đơn giản như vậy!

Vai trò của Cost Optimizer

Hầu hết các hệ quản trị cơ sở dữ liệu (DBMS) hiện đại như MySQL, PostgreSQL, SQL Server, hay Oracle đều có một thành phần gọi là Cost Optimizer (trình tối ưu hóa chi phí). Đây là "bộ não" của DBMS, chịu trách nhiệm phân tích câu query và quyết định cách thực thi hiệu quả nhất. Dưới đây là cách nó hoạt động:

  1. Phân tích cú pháp (Parsing): DBMS kiểm tra cú pháp của query để đảm bảo không có lỗi.

  2. Tối ưu hóa (Optimization): Cost Optimizer đánh giá nhiều execution plans khác nhau. Nó xem xét:

    • Kích thước của các bảng.

    • Indexes.

    • Data statistics.

    • Các điều kiện trong WHERE và JOIN.

  3. Lựa chọn kế hoạch tốt nhất: Optimizer chọn kế hoạch có chi phí thấp nhất (dựa trên CPU, I/O, bộ nhớ, v.v.) và thực thi.

Vậy có thể nói, thứ tự bạn viết WHERE và JOIN trong query không quyết định thứ tự thực thi. Cost Optimizer sẽ tự động sắp xếp lại các thao tác để đạt hiệu suất tối ưu.

Ví dụ cụ thể

Hãy xem xét hai bảng sau:

  • customers (10,000 bản ghi): Chứa thông tin khách hàng.

  • orders (100,000 bản ghi): Chứa thông tin đơn hàng.

Query 1: JOIN trước, WHERE sau

SELECT c.customer_name, o.order_date
FROM customers c
JOIN orders o ON c.customer_id = o.customer_id
WHERE c.country = 'Vietnam';

Query 2: Lọc WHERE trước (giả thuyết) Một số người nghĩ rằng nếu lọc customers trước, query sẽ nhanh hơn:

SELECT c.customer_name, o.order_date
FROM (SELECT * FROM customers WHERE country = 'Vietnam') c
JOIN orders o ON c.customer_id = o.customer_id;

Phân tích

  • Trong Query 1, bạn viết JOIN trước, sau đó mới lọc WHERE.

  • Trong Query 2, bạn cố gắng lọc customers trước khi JOIN.

Tuy nhiên, với Cost Optimizer, hai query này thường được xử lý tương tự. Nếu có index trên cột country của bảng customers và cột customer_id của cả hai bảng, Optimizer sẽ:

  • Lọc bảng customers trước, dùng index idx_country để tìm nhanh các khách hàng có country = 'Vietnam'.

  • Rồi nó JOIN với bảng orders, dùng index idx_customer_id để khớp customer_id.

  • Dù mình viết JOIN trước WHERE, Optimizer cũng sẽ tự quyết định lọc trước, rồi mới JOIN

Bạn có thể kiểm tra kế hoạch thực thi bằng cách sử dụng EXPLAIN (hoặc EXPLAIN PLAN trong một số DBMS) để thấy Optimizer thực sự làm gì. Ví dụ, trong MySQL:

EXPLAIN
SELECT c.customer_name, o.order_date
FROM customers c
JOIN orders o ON c.customer_id = o.customer_id
WHERE c.country = 'Vietnam';

Kết quả sẽ cho thấy Optimizer có thể đã áp dụng điều kiện WHERE trước JOIN nếu điều đó hiệu quả hơn, bất kể thứ tự bạn viết.

Khi nào thứ tự có thể ảnh hưởng?

Mặc dù Cost Optimizer rất thông minh, nó không phải lúc nào cũng hoàn hảo. Trong một số trường hợp hiếm hoi, bạn có thể cần can thiệp:

  • Thiếu Indexes: Nếu không có chỉ mục trên các cột được sử dụng trong WHERE hoặc JOIN, Optimizer có thể đưa ra kế hoạch không tối ưu.

  • Stale statistic: Nếu thống kê về dữ liệu không được cập nhật, Optimizer có thể đánh giá sai chi phí.

  • Query phức tạp: Với các query có nhiều JOIN, subquery, hoặc hàm phức tạp, bạn có thể cần ép DBMS thực thi theo cách cụ thể.

Tối ưu khi sử dụng Cost Optimizer

  1. Tạo index: Đảm bảo các cột trong WHERE và JOIN có chỉ mục phù hợp.

  2. Viết query rõ ràng: Dù Optimizer thông minh, hãy viết query dễ đọc và logic để hỗ trợ bảo trì code.

  3. Kiểm tra kế hoạch thực thi: Sử dụng EXPLAIN để hiểu cách query được thực thi.

Tất nhiên còn rất nhiều cách tối ưu khác, nhưng đó ko phải trọng tâm của bài viết này, các bạn tự tìm hiểu nhé =)))

Kết luận

Câu hỏi "Nên đặt WHERE trước hay JOIN trước?" thực chất không ảnh hưởng nhiều đến hiệu suất, vì Cost Optimizer của DBMS sẽ tự động tối ưu hóa thứ tự thực thi dựa trên chi phí. Thay vì lo lắng về thứ tự viết, hãy tập trung vào việc optimize nó theo các cách kể trên.

Hãy để Cost Optimizer làm việc của nó, và bạn chỉ cần viết SQL rõ ràng, dễ hiểu. Chúc bạn thành công trong việc tối ưu hóa các câu query SQL!

Bình luận

Bài viết tương tự

- vừa được xem lúc

Giới thiệu Stored Procedure trong SQL Server

Stored Procedure là 1 phần không thể thiếu của SQL Server. Chúng có thể hỗ trợ rất nhiều cho lập trình và cấu hình cơ sở dữ liệu.

0 0 170

- vừa được xem lúc

sử dụng index trong sql query

Index là một trong những yếu tố quan trọng nhất góp phần vào việc nâng cao hiệu suất của cơ sở dữ liệu. Index trong SQL tăng tốc độ của quá trình truy vấn dữ liệu bằng cách cung cấp phương pháp truy xuất nhanh chóng tới các dòng trong các bảng, tương tự như cách mà mục lục của một cuốn sách giúp bạn

0 0 270

- vừa được xem lúc

Hướng dẫn sửa lỗi không cài được SQL Server

Hôm qua do yêu cầu môn học, mình có cài lại Microsoft SQL Server. Trước đó mình có cài rồi, nhưng rồi lâu không dùng nên gỡ ra cho nhẹ máy. Bây giờ có dịp cần nên mình mới cài lại. Chi tiết lỗi mình gặp phải.

0 0 142

- vừa được xem lúc

Bạn nên tránh sử dụng Soft Delete khi có thể, và đây là lý do tại sao

Con người luôn luôn mắc sai lầm. Vì vậy, việc "lo xa" trước mọi tình huống xấu nhất chưa bao giờ là thừa.

0 0 210

- vừa được xem lúc

Sử dụng trigger trong SQL qua ví dụ cơ bản.

Trigger là gì . Cú pháp của Trigger. CREATE TRIGGER tên_trigger ON tên_bảng. FOR {DELETE, INSERT, UPDATE}.

0 0 169

- vừa được xem lúc

Khác biệt giữa khóa chính và khóa ngoại trong SQL

Các khoá chính và khóa ngoại là hai loại ràng buộc có thể được sử dụng để thực thi toàn vẹn dữ liệu trong các bảng SQL Server và đây là những đối tượng cơ sở dữ liệu quan trọng. Trong bài này, tôi muố

0 0 159