Tối ưu (turning) câu lệnh PL/SQL: Việc JOIN và lấy dữ liệu trong câu lệnh SELECT

Trước đây ở công ty C mình cũng ít làm việc về Report nhưng các hàm query lấy dữ liệu thì cũng phải dùng thường xuyên. Các anh làm về Database cũng hay cảnh báo mọi người việc sử dụng câu lệnh SELECT ALL thì không được dùng. Việc SELECT ALL là câu lệnh SELECT *, cũng như việc SELECT những cái gì cần lấy chứ không nên lấy những cột mà không cần dùng.
Câu lệnh SELECT liên quan đến chỉ số I/O của hệ thống. SELECT càng nhiều thì càng làm tăng I/O và ảnh hưởng đến hiệu năng của hệ thống. Nôm na I/O là Input và Output giữa đĩa cứng để dữ liệu và RAM của server, dữ liệu sẽ đi qua cổng I/O này và nếu lớn nó sẽ làm ngẽn hệ thống.
Ví dụ điển hình là câu lệnh:
(1) SELECT COUNT(*) FROM TABLE_A WHERE A=B;
sẽ cho cùng kết quả với câu lệnh:
(2) SELECT COUNT(COLUMN_A1) FROM TABLE_A WHERE A=B;
và câu lệnh:
(3) SELECT COUNT(1) FROM TABLE_A WHERE A=B;

Với câu lệnh 1, hệ thống sẽ lấy toàn bộ các cột dữ liệu và tiến hành đếm các dòng ở các cột này. Việc này sẽ làm tăng I/O ảnh hưởng đến hệ thống và tất nhiên chạy chậm hơn.
Với câu lệnh 2, hệ thống sẽ lấy 1 cột COLUMN_A1 dữ liệu và tiến hành đếm các dòng ở các cột này. Câu lệnh này hệ thống cũng sẽ lấy dữ liệu ở cột COLUMN_A1 ra và đếm, I/O tốn ít hơn và câu lệnh sẽ nhanh hơn.
Với câu lệnh 3, hệ thống sẽ tự hiểu việc sẽ đếm toàn bộ các dòng trong bảng theo điều kiện gì đó. Hệ thống sẽ cần rất ít I/O nên câu lệnh sẽ nhanh hơn và đảm bảo được hiệu năng của hệ thống.

Từ lý thuyết về I/O và ví dụ trên, ta có thể tối ưu các câu lệnh JOIN và lấy dữ liệu sao cho hợp lý, tối ưu được hiệu năng hệ thống nhất là chỉ số I/O. Tránh việc gây nghẽn hệ thống, làm hệ thống giảm được tải, các câu lệnh chạy được nhanh hơn.

Ví dụ:
Câu lệnh chưa tối ưu: Lấy lương từng nhân sự phòng IT của tháng 12/2018

SELECT EP.ID,EP.NAME,SL.AMOUNT
FROM EMPLOYEE EP, SALARY SL
WHERE EP.ID=SL.ID
AND EP.IDDE='IT'
AND SL.MONTH='201812';

Ta có thể tối ưu lại để đỡ tốn I/O như sau:

SELECT EP.ID,EP.NAME,SL.AMOUNT
FROM (SELECT ID,NAME FROM EMPLOYEE WHERE IDDE='IT') EP, (SELECT EPID,AMOUNT FROM SALARY WHERE MONTH='201812') SL
WHERE EP.ID=SL.EPID;

Phần này ta đã giảm I/O bằng cách thay vì lấy toàn bộ dữ liệu bảng SALARY, EMPLOYEE ra để tiến hành JOIN sau đó mới lọc thì ta tiến hành lọc và lấy xác định các cột từ trước sau đó mới tiến hành JOIN vào với các điều kiện để lấy dữ liệu.
Đây chỉ là một ví dụ đơn giản để ta hiểu việc chỉ lấy dữ liệu cần thiết khi dùng thôi, còn thực tế thì phải tùy theo độ phức tạp để lấy dữ liệu một cách hiệu quả.