Khi bắt đầu tiếp cận SQL, tôi từng mang theo một giả định rất tự nhiên: Dòng nào được viết trước, hệ thống sẽ đọc và xử lý dòng đó trước.
Giả định này hình thành từ thói quen tư duy thông thường. Từ việc đọc một văn bản cho đến các công cụ quen thuộc như Power Query hay Excel, các bước biến đổi dữ liệu luôn diễn ra tuần tự: bước 1 hoàn thành mới chuyển sang bước 2, rồi mới tới bước 3.
Tuy nhiên, trong kiến trúc của cơ sở dữ liệu quan hệ, giả định này lại là nguyên nhân dẫn đến một trong những lỗi kinh điển nhất của người mới viết code.
Bạn soạn thảo một câu lệnh đúng cú pháp, đặt tên cho một cột tính toán mới rất rõ ràng ở ngay dòng đầu tiên. Nhưng khi nhấn thực thi, Database Engine lập tức trả về lỗi: Unknown column ....
1. Một tình huống kỹ thuật quen thuộc
Xét câu truy vấn cơ bản trên bảng thanh toán payments:

Mục tiêu xử lý của người viết rất tường minh:
Trích xuất mã khách hàng (
customerNumber).Tính toán cột mới tên là
taxbằng 10% của số tiền (amount * 0.1).Lọc lấy những bản ghi có
taxlớn hơn 5,000.
Về mặt cú pháp văn bản, câu lệnh hoàn chỉnh. Tuy nhiên, Database Engine sẽ từ chối thực thi với thông báo:

Nguyên nhân nào khiến hệ thống không nhận diện một định danh đã được khai báo ở ngay dòng thứ 2 của câu lệnh?
2. Bản chất: "Trình tự cú pháp" đối đầu "Trật tự xử lý logic"
Vấn đề bắt nguồn từ sự phân tách giữa hai cơ chế: Trật tự trình bày cú pháp (Lexical Order) và Trật tự xử lý logic (Logical Processing Order).
SQL được thiết kế vào thập niên 1970 nhằm mô phỏng cấu trúc ngữ pháp tiếng Anh để con người dễ đọc hiểu. Trong giao tiếp, mục tiêu đầu ra luôn được nêu trước: "Chọn tài liệu A từ thư mục B nếu thỏa điều kiện C". Đó là lý do từ khóa SELECT xuất hiện ở dòng đầu tiên.
Thế nhưng, quy trình biên dịch và tối ưu hóa truy vấn của Database Engine không vận hành theo thói quen đọc của con người. Trọng tâm của Database Engine là hiệu năng và tối ưu tài nguyên: làm thế nào để xử lý tập dữ liệu với chi phí đọc đĩa (I/O) và dung lượng RAM thấp nhất.
Về mặt kỹ thuật, hệ thống không thể tính toán biểu thức hay trích xuất các cột (SELECT) khi chưa xác định được bảng nguồn (FROM) lưu trữ ở đâu trên đĩa cứng.
Do đó, khi nhận câu lệnh, Database Engine sẽ phân tích cú pháp (parse) và tái sắp xếp thành một trật tự xử lý logic hoàn toàn khác:

3. Phân tích cơ chế phát sinh lỗi
Nhìn vào trật tự xử lý logic của hệ thống, bản chất của các trường hợp báo lỗi hay thực thi thành công trở nên rõ ràng:
· Vì sao WHERE không nhận diện được alias tax?
Giai đoạn WHERE diễn ra ở bước 2, ngay sau khi hệ thống quét dữ liệu từ bảng nguồn. Mục tiêu ở giai đoạn này là loại bỏ tối đa các dòng không cần thiết để giảm tải dung lượng nạp vào bộ nhớ tạm.
Trong khi đó, mệnh đề SELECT chỉ được kích hoạt ở bước 5.
Tại thời điểm mệnh đề WHERE quét từng bản ghi thô, biểu thức amount * 0.1 chưa hề được tính toán, và định danh tax chưa tồn tại trong không gian tên (namespace) của bộ nhớ. Việc Database Engine báo lỗi Unknown column là kết quả hoàn toàn chính xác theo đúng chu trình xử lý dữ liệu.
· Vì sao ORDER BY ở cuối câu lại sử dụng alias hợp lệ?
Nếu thay đổi điều kiện sang sắp xếp:

Câu lệnh sẽ thực thi bình thường.
Bởi vì ORDER BY nằm ở bước 6 — giai đoạn diễn ra sau khi mệnh đề SELECT (bước 5) đã hoàn tất việc tính toán giá trị và gắn nhãn alias cho từng cột. Tại thời điểm này, tập dữ liệu kết quả đã thành hình, cho phép thao tác sắp xếp truy cập trực tiếp vào định danh tax.
4. Viết code thế nào cho đúng với trật tự thực thi?
Khi đã hiểu Database Engine vận hành theo thứ tự nào, bạn sẽ không còn sửa lỗi theo kiểu đoán mò.
Giải pháp cho bài toán lọc này thực chất rất đơn giản: Đưa trực tiếp biểu thức tính toán vào mệnh đề WHERE thay vì dùng alias.

Bạn không cần lo lắng về việc Database Engine phải tính toán biểu thức hai lần. Thực tế, các bộ tối ưu hóa truy vấn hiện đại (Query Optimizer) đủ thông minh để nhận diện và gộp các phép toán trùng lặp này lại mà không làm suy giảm hiệu năng.
Nắm bắt trật tự thực thi logic là bước chuyển quan trọng từ việc chỉ nhớ cú pháp rời rạc sang việc thực sự hiểu cách hệ thống vận hành. Khi câu lệnh được thiết kế tương thích với quy trình xử lý nội bộ, bạn sẽ không còn phải loay hoay trước những thông báo lỗi tưởng chừng vô lý của SQL.

Bình luận
0 bình luậnViết bình luận
Chưa có bình luận nào. Hãy bắt đầu cuộc trò chuyện.