Chuyển đến nội dung chính

Thứ tự thực thi SQL: Hiểu cách truy vấn chạy

Hiểu thứ tự thực thi SQL và cách nó khác với thứ tự viết. Viết truy vấn chính xác, tối ưu để cải thiện hiệu năng và tránh các lỗi thường gặp trong thiết kế truy vấn.
Đã cập nhật 5 thg 6, 2026  · 5 phút đọc

Khi viết truy vấn SQL, chúng ta thường theo một thứ tự nhất định (SQL thường được viết theo kiểu từ trong ra ngoài). Tuy nhiên, các bộ máy SQL lại tuân theo một thứ tự thực thi cụ thể khi biên dịch truy vấn, khác với thứ tự viết thông thường. Hiểu thứ tự thực thi SQL rất quan trọng để làm chủ tối ưu hóa truy vấn, cải thiện độ chính xác và hiệu năng, cũng như gỡ lỗi các vấn đề phức tạp, như bạn sẽ thấy dưới đây.

Khi bắt đầu, tôi khuyến nghị bạn học khóa Introduction to SQL và lộ trình kỹ năng SQL Fundamentals của DataCamp để nắm vững những kiến thức cơ bản về SQL và cách trích xuất dữ liệu bằng truy vấn. SQL Basics Cheat Sheet cũng sẽ là một hướng dẫn hữu ích cho các hàm SQL phổ biến dùng để lọc và tổng hợp dữ liệu.

Thứ tự thực thi SQL là gì?

Thứ tự thực thi SQL đề cập đến trình tự các mệnh đề khác nhau trong truy vấn được đánh giá. Đáng để hiểu bởi vì thứ tự thực thi thường khác với cách chúng ta viết truy vấn SQL. Lấy ví dụ đơn giản nhất, bạn có thể nghĩ rằng trong trường hợp SELECT * FROM database, SELECT được đánh giá trước, nhưng thực tế thứ tự thực thi bắt đầu với mệnh đề FROM.

Dưới đây là thứ tự thực thi SQL. Ở phần tiếp theo, chúng ta sẽ đi chi tiết từng bước. 

  • FROM/JOIN: Chỉ định các bảng cần truy xuất dữ liệu.
  • WHERE: Lọc các dòng thỏa điều kiện trước khi nhóm.
  • GROUP BY: Nhóm các dòng có cùng một thuộc tính.
  • HAVING: Lọc các nhóm dựa trên điều kiện, áp dụng sau khi nhóm.
  • SELECT: Chỉ định các cột cần truy xuất hoặc tính toán.
  • DISTINCT: Loại bỏ các dòng trùng lặp khỏi tập kết quả.
  • ORDER BY: Sắp xếp tập kết quả theo các cột chỉ định.
  • LIMIT: Chỉ định số dòng tối đa cần trả về.
  • OFFSET: Chỉ định số dòng cần bỏ qua trước khi bắt đầu trả về.

Trong truy vấn dưới đây, tôi đã thêm chú thích để cho biết phần nào được đánh giá trước. 

-- #6+7   SELECT DISTINCT department_id                                 
-- #1     FROM employees                                                
-- #2     JOIN orders ON customers.customer_id = orders.customer_id     
-- #3     WHERE salary > 3000                                          
-- #4     GROUP BY department 
-- #5     HAVING AVG(salary) > 5000 
-- #8     ORDER BY department 
-- #9     LIMIT 10 OFFSET 5 
-- #10    OFFSET 5 ROWS FETCH NEXT 10 ROWS ONLY; 

Tôi cũng nghĩ ra một câu nhớ dễ thuộc: For Work Goals and Hurdles hãy Search DataCamp's Organized Learning Opportunities.

Các giai đoạn thực thi truy vấn SQL

Mặc dù hầu hết truy vấn SQL chúng ta viết bắt đầu bằng câu lệnh SELECT, thứ tự thực thi logic lại bắt đầu với mệnh đề FROM. Ở đây, tôi sẽ viết các truy vấn để minh họa thứ tự thực thi truy vấn. Tuy nhiên, lưu ý rằng các truy vấn này chưa hoàn chỉnh và sẽ không biên dịch được.

Mệnh đề FROM

Truy vấn SQL bắt đầu quá trình thực thi với mệnh đề FROM. Đây thường là giai đoạn đầu tiên vì cơ sở dữ liệu xác định nguồn dữ liệu/các bảng. Khi có nhiều bảng, truy vấn SQL cũng sẽ đánh giá điều kiện JOIN để kết hợp các bảng được chỉ định làm nguồn dữ liệu.

Truy vấn chưa hoàn chỉnh dưới đây sẽ trước hết chọn dữ liệu từ bảng customers bằng mệnh đề FROM và bảng orders bằng mệnh đề JOIN.

FROM customers
JOIN orders ON customers.customer_id = orders.customer_id;

Mệnh đề WHERE

Mệnh đề WHERE được thực thi sau FROMJOIN để lọc các dòng dựa trên điều kiện cụ thể. Cần lưu ý rằng các cột được đặt bí danh trong mệnh đề SELECT không thể được tham chiếu trực tiếp trong WHERE vì nó được xử lý trước SELECT

Truy vấn dưới đây dùng mệnh đề WHERE để lọc các bản ghi nhân viên có bonus lớn hơn 5000.

FROM employees
JOIN departments ON employees.employee_id = departments.department_id
WHERE salary * 0.1 > 5000;

Mệnh đề GROUP BY

Sau khi lọc các dòng, SQL thực thi mệnh đề GROUP BY để nhóm kết quả theo các cột chỉ định. Bước này thường dùng kèm các hàm tổng hợp như COUNT(), SUM()AVG() để thực hiện tính toán trên các cột chỉ định.

Truy vấn dưới đây trước hết lọc những nhân viên có salary lớn hơn 3,000, sau đó nhóm theo department và tính lương trung bình cho mỗi nhóm.

FROM employees e
JOIN departments d ON e.employee_id = d.department_id
WHERE e.salary > 3000
GROUP BY e.name, d.department_name;

Mệnh đề HAVING

Mệnh đề HAVING tương tự WHERE nhưng dùng để lọc dữ liệu đã được nhóm sau thao tác GROUP BY. Trong truy vấn dưới đây, SQL nhóm employees theo department, tính lương trung bình cho mỗi nhóm, rồi lọc ra các nhóm có lương trung bình nhỏ hơn hoặc bằng 5,000

FROM employees
JOIN departments ON employees.employee_id = departments.department_id
WHERE salary > 3000
GROUP BY department_name
HAVING AVG(salary) > 5000;

Mệnh đề SELECT

Mệnh đề SELECT là nơi SQL xác định các cột hoặc biểu thức sẽ trả về sau khi thực thi các bước trước đó. Bạn có thể áp dụng phép toán, đặt bí danh và các hàm tổng hợp trong mệnh đề SELECT.

Truy vấn sau sử dụng mệnh đề SELECT để truy xuất namebonus được tính là salary * 0.1 từ bảng employees.

SELECT name, salary * 0.1 AS bonus
FROM employees
JOIN orders ON customers.customer_id = orders.customer_id
WHERE salary > 3000
GROUP BY name
HAVING AVG(salary) > 5000;

Mệnh đề DISTINCT

Mệnh đề DISTINCT được đánh giá sau mệnh đề SELECT trong một truy vấn. DISTINCT quan trọng để loại bỏ các bản ghi trùng lặp vì nó trả về các dòng duy nhất. Truy vấn dưới đây trả về mỗi department_id duy nhất, loại bỏ bản trùng.

SELECT DISTINCT department_id
FROM employees
JOIN orders ON customers.customer_id = orders.customer_id
WHERE salary > 3000
GROUP BY department
HAVING AVG(salary) > 5000;

Mệnh đề ORDER BY

Mệnh đề ORDER BY sắp xếp tập kết quả theo các cột hoặc biểu thức cụ thể. Không giống mệnh đề WHERE, ORDER BY có thể dùng các bí danh cột được định nghĩa trong câu lệnh SELECT.

Truy vấn dưới đây sắp xếp cột bonus theo thứ tự giảm dần. Lưu ý bonus được định nghĩa trong câu lệnh SELECT như một bí danh của một biểu thức.

SELECT DISTINCT department_id
FROM employees
JOIN orders ON customers.customer_id = orders.customer_id
WHERE salary > 3000
GROUP BY department
HAVING AVG(salary) > 5000
ORDER BY bonus DESC;

Mệnh đề LIMIT/OFFSET

Các mệnh đề LIMITOFFSET thường là phần được thực thi cuối cùng trong truy vấn SQL để giới hạn số dòng trả về. LIMIT chỉ định số dòng tối đa cần trả về, còn OFFSET chỉ định số dòng cần bỏ qua trước khi bắt đầu trả về.

Truy vấn dưới đây truy xuất tên và lương của nhân viên, sắp xếp theo salary giảm dần, và giới hạn đầu ra ở 10 kết quả trong khi bỏ qua 5 dòng đầu tiên.

SELECT DISTINCT department_id
FROM employees
JOIN orders ON customers.customer_id = orders.customer_id
WHERE salary > 3000
GROUP BY department
HAVING AVG(salary) > 5000
ORDER BY bonus DESC
LIMIT 10 OFFSET 5;
-- OFFSET 5 ROWS FETCH NEXT 10 ROWS ONLY --SQL SERVER / ORACLE

Các mệnh đề LIMITOFFSET được hỗ trợ trong cơ sở dữ liệu MySQL và PostgreSQL. Với SQL Server và Oracle, bạn dùng OFFSET, ROWS FETCHROWS ONLY để giới hạn số dòng trả về từ một truy vấn.

Xem hướng dẫn Cách dùng SQL OFFSET để tìm hiểu thêm về phân trang dữ liệu và hỗ trợ cụ thể theo từng hệ quản trị cho các mệnh đề OFFSETLIMIT.

Thứ tự thực thi SQL so với thứ tự viết

SQL là ngôn ngữ khai báo, nghĩa là thứ tự thực thi truy vấn khác với thứ tự viết. Thay vì chỉ định cách thực hiện một tác vụ, bạn khai báo điều bạn muốn, và bộ máy cơ sở dữ liệu sẽ quyết định cách tốt nhất để đạt được điều đó. Cách này khác với các ngôn ngữ lập trình mệnh lệnh như Python hay Java, nơi bạn viết tường minh các bước thực thi. 

Hiểu thứ tự thực thi SQL sẽ thay đổi cách bạn nghĩ về việc xây dựng truy vấn. Ví dụ, hãy tưởng tượng bạn viết một truy vấn để lọc các dòng dựa trên một bí danh bạn tạo trong mệnh đề SELECT:

SELECT price * 0.9 AS discounted_price
FROM products
WHERE discounted_price > 100;

Nhìn qua thì có vẻ hợp lý, nhưng truy vấn này sẽ báo lỗi. Tại sao? Vì mệnh đề WHERE được đánh giá trước mệnh đề SELECT trong thứ tự thực thi của SQL. Để khắc phục, bạn cần dùng một truy vấn con hoặc dùng HAVING thay thế:

SELECT price * 0.9 AS discounted_price
FROM products
HAVING discounted_price > 100;

Để tìm hiểu thêm cụ thể về WHEREHAVING, hãy đọc hướng dẫn của chúng tôi: Sự khác nhau giữa WHERE và HAVING trong SQL.

Lỗi thường gặp và thực hành tốt nhất

Mặc dù thứ tự thực thi truy vấn không bị ảnh hưởng bởi thứ tự viết, hiểu luồng thực thi là rất quan trọng để tránh các lỗi thường gặp và cải thiện hiệu năng. Các lỗi sau liên quan trực tiếp đến việc hiểu sai thứ tự thực thi của SQL:

Lỗi thường gặp

Dưới đây là các lỗi phổ biến có thể cản trở hiệu năng truy vấn của bạn.

  • Dùng bí danh cột trong mệnh đề WHERE: Vì mệnh đề WHERE được thực thi trước SELECT, việc cố dùng bí danh trong WHERE sẽ gây lỗi. Hiểu rằng SQL đánh giá WHERE trước SELECT cho bạn biết cần lặp lại đầy đủ biểu thức thay vì dựa vào bí danh.

  • Dùng HAVING để lọc dòng thay vì WHERE: Mệnh đề HAVING được thực thi sau GROUP BY và được thiết kế để lọc dữ liệu đã tổng hợp. Nếu bạn lọc dữ liệu chưa tổng hợp, điều kiện đó thuộc về mệnh đề WHERE. Biết sự khác biệt về thứ tự thực thi giữa WHERE và HAVING sẽ giúp bạn xác định vị trí phù hợp cho từng điều kiện.

  • Dùng hàm tổng hợp trong SELECT mà không có GROUP BY: Vì GROUP BY được thực thi trước HAVING hoặc SELECT, không nhóm dữ liệu trước khi áp dụng hàm tổng hợp sẽ dẫn đến kết quả sai hoặc lỗi. Hiểu thứ tự thực thi làm rõ vì sao hai mệnh đề này cần đi cùng nhau.

  • Không dùng bí danh đúng cách trong mệnh đề ORDER BY: Khác với WHERE, mệnh đề ORDER BY được đánh giá sau SELECT. Điều này cho phép bạn dùng các bí danh tạo trong SELECT để sắp xếp, giúp tránh nhầm lẫn bằng cách biết khi nào bí danh sẵn sàng để sử dụng.

Thực hành tốt nhất

Cân nhắc các thực hành tốt nhất dưới đây để đảm bảo truy vấn của bạn thực thi như mong đợi.

  • Lọc sớm với WHERE: Vì mệnh đề WHERE được thực thi trước GROUP BYJOIN, áp dụng bộ lọc sớm sẽ giảm số dòng được xử lý bởi các mệnh đề tiếp theo, cải thiện hiệu năng. Bằng cách lọc dữ liệu chưa tổng hợp càng sớm càng tốt, bạn giới hạn lượng dữ liệu cần nhóm hoặc nối, tiết kiệm thời gian xử lý.

  • Tiền tổng hợp dữ liệu trước khi JOIN: Biết rằng FROMJOIN là các mệnh đề được thực thi đầu tiên, việc tiền tổng hợp dữ liệu bằng truy vấn con hoặc CTE giúp thu nhỏ tập dữ liệu trước khi thực hiện nối. Nhờ đó, ít dòng hơn được xử lý trong quá trình nối.

  • Tối ưu ORDER BY với chỉ mục: Vì ORDER BY là một trong các bước được thực thi cuối, đảm bảo các cột sắp xếp có chỉ mục sẽ tăng tốc hiệu năng bằng cách giúp cơ sở dữ liệu xử lý thao tác sắp xếp hiệu quả hơn.

  • Tránh SELECT * trong truy vấn sản xuất: Mệnh đề SELECT được thực thi sau khi lọc, nhóm và tổng hợp, nên chỉ định đúng các cột cần thiết sẽ giảm lượng dữ liệu truy xuất, hạn chế chi phí không cần thiết.

Kết luận

Hiểu thứ tự thực thi SQL rất quan trọng để viết các truy vấn hiệu quả, chính xác và được tối ưu. Chúng ta đã thảo luận về thứ tự thực thi logic của truy vấn trong SQL và so sánh với thứ tự viết. Tôi khuyến khích bạn luyện viết nhiều truy vấn khác nhau để hiểu rõ hơn thứ tự thực thi logic. Làm chủ khái niệm này sẽ cải thiện đáng kể khả năng gỡ lỗi và tối ưu truy vấn SQL của bạn.

Nếu bạn muốn nâng cao kỹ năng SQL, tôi khuyên bạn thử lộ trình nghề nghiệp Associate Data Analyst in SQL của DataCamp để trở thành một nhà phân tích dữ liệu thành thạo. Khóa Reporting in SQL cũng sẽ giúp bạn thành thạo xây dựng các báo cáo và bảng điều khiển phức tạp để trình bày dữ liệu hiệu quả. Cuối cùng, bạn nên lấy SQL Associate Certification để chứng minh khả năng dùng SQL giải quyết bài toán kinh doanh và nổi bật giữa các chuyên gia khác.


Allan Ouko's photo
Author
Allan Ouko
LinkedIn
Biên tập viên kỹ thuật về Khoa học dữ liệu với kinh nghiệm thực tế trong phân tích dữ liệu, trí tuệ doanh nghiệp và khoa học dữ liệu. Tôi viết nội dung thực tiễn, tập trung vào ngành về SQL, Python, Power BI, Databricks và kỹ thuật dữ liệu, dựa trên công việc phân tích trong thế giới thực. Bài viết của tôi kết nối chiều sâu kỹ thuật với tác động kinh doanh, giúp các chuyên gia chuyển đổi dữ liệu thành những quyết định vững chắc.

Câu hỏi thường gặp về Thứ tự thực thi SQL

Thực thi SQL khác gì với thứ tự viết?

Thứ tự thực thi SQL thường bắt đầu với mệnh đề FROM tiếp theo là các mệnh đề như WHEREGROUP BY trong khi thứ tự viết bắt đầu bằng câu lệnh SELECT.

JOIN nằm ở đâu trong thứ tự thực thi?

Các phép JOIN được thực thi như một phần của mệnh đề FROM.

Tôi có thể dùng bí danh cột trong mệnh đề WHERE không?

Không, bí danh cột được định nghĩa trong mệnh đề SELECT, được thực thi sau mệnh đề WHERE.

Sự khác nhau giữa WHERE và HAVING là gì?

WHERE lọc các dòng trước khi nhóm, trong khi HAVING lọc sau GROUP BY và hoạt động trên dữ liệu đã tổng hợp.

Thứ tự thực thi SQL có ảnh hưởng đến hiệu năng truy vấn không?

Có, hiểu thứ tự thực thi cho phép bạn tối ưu truy vấn bằng cách áp dụng bộ lọc sớm và giảm các thao tác không cần thiết.

Chủ đề

Học SQL với DataCamp

Courses

Xử lý dữ liệu trong SQL

4 giờ
323.5K
Xem chi tiếtRight Arrow
Bắt đầu khóa học
Xem thêmRight Arrow