Tối ưu câu lệnh truy vấn SQL

Hiệu suất làm việc của ứng dụng bị ảnh hưởng bởi nhiều yếu tố khác nhau. Một trong các yếu tố đó chính là việc hệ thống mất bao nhiêu thời gian để xử lý câu lệnh SQL của bạn phía máy chủ dữ liệu. Đôi khi việc thiết kế cấu trúc database và các truy vấn phức tạp sẽ cản trở rất nhiều đến khả năng truy xuất dữ liệu của ứng dụng. Bằng cách kiểm tra và tối ưu các câu truy vấn SQL, bạn có thể giúp SQL Server tối ưu hóa và cải thiện hiệu suất.

Tối ưu hóa câu truy vấn SQL

Làm thế nào để tối ưu câu lệnh truy vấn SQL?

Chỉ định rõ ràng tên column trong câu lệnh SELECT

Đã bao nhiêu lần bạn viết câu lệnh SQL tương tự như thế này ?

SELECT * FROM MyTable;

Sử dụng dấu hoa thị (*) với mục đích là bạn muốn trả lại tất cả các cột từ bảng hoặc các bảng được xác định trong mệnh đề FROM. Đó không phải là một thói quen tốt, ngay cả khi bạn muốn lấy giá trị của tất cả các cột trong bảng. Sẽ là tốt hơn nếu bạn xác định tên cột một cách rõ ràng như thế này:

 SELECT ID, Description, DateModified FROM MyTable;

Sử dụng tên rõ ràng của các cột trong các câu lệnh SELECT có một số lợi thế. Đầu tiên, SQL Server chỉ trả lại chính xác những gì mà ứng dụng của bạn cần, chứ không phải là tất cả dữ liệu mà trong đó ứng dụng của bạn chỉ sử dụng một lượng dữ liệu ít trong số đó. Bằng cách này, bạn đang giúp cho SQL Server không phải đi tìm xem trong bảng bạn đang truy xuất có những cột nào để nó có thể lấy dữ liệu ra từ đó. Cũng bằng cách không sử dụng dấu sao (*), bạn cũng giảm thiểu được băng thông khi lưu lượng dữ liệu gửi đi trên đường truyền ít hơn, dẫn đến tăng tốc ứng dụng.

Ngoài ra, bạn cũng có thể tránh được lỗi có thể xảy ra nếu sau này bạn có thay đổi gì đó liên quan đến mối liên hệ (relationship) giữa các bảng. Nếu bạn đã sử dụng dấu (*) cho truy vấn, sau đó có một ai đó thêm một cột vào, thì ứng dụng của bạn sẽ nhận cả dữ liệu từ cột này vào truy vấn, ngay cả khi bạn không có thay đổi gì trong code ứng dụng. Lúc đó, nếu ứng dụng của bạn chỉ thiết kế để nhận các cột dữ liệu cố định nào đó để truy xuất, có thể lỗi sẽ xảy ra. Vì vậy, xác định rõ ràng tên cột sẽ mang lại hiệu suất tốt hơn và đảm bảo cho ứng dụng của bạn hoạt động tốt hơn, thậm chí ngay cả khi có thay đổi nào đó liên quan đến cấu trúc.

Xác định rõ tên cột trong câu lệnh INSERT

Tương tự như trên, nên xác định rõ ràng các cột trong câu lệnh INSERT. Đừng bao giờ viết câu lệnh INSERT kiểu như thế này:

 INSERT INTO MyTable VALUES ('A', 'B', 'C');

Khi bạn viết như thế này, SQL Server sẽ sử dụng ba cột đầu tiên trong bảng bạn đang Insert vào, giá trị ‘A’ sẽ chèn vào cột đầu tiên, ‘B’ sẽ vào cột thứ 2, và ‘C’ cho cột thứ 3. Nếu ai đó vô tình chèn thêm một cột vào bảng thì ngay lập tức mọi trật tự trong câu lệnh của bạn sẽ bị phá vỡ.

Vì vậy, thay vì sử dụng câu lệnh INSERT như trên, bạn nên code như thế này:

INSERT INTO MyTable (FirstCode, SecondCode, ThirdCode) VALUES ('A', 'B', 'C');

Tối ưu tốc độ tìm kiếm khi sử dụng các ký tự đại diện (wildcard)

Sử dụng ký tự đại diện hợp lý có thể cải thiện hiệu suất của các truy vấn của bạn. Giả sử bạn muốn tìm kiếm bảng AdventureWorks.Person.Contact với LastNames kết thúc bằng “sen”. Giả sử rằng bạn cũng đã xây dựng một chỉ mục trên cột LastName. Nếu câu lệnh của bạn như thế này:

SELECT DISTINCT LastName
FROM Person.Contac
WHERE LastName LIKE '%sen'

Đoạn codde này sử dụng ký tự đại diện % để tìm các chuỗi ký tự mà phía sau nó là chữ “sen”, chuỗi ký tự này có thể có độ dài 0 hoặc nhiều. Để thực hiện việc này, SQL Server thực hiện hoạt động quét chỉ mục tìm kiếm tất cả các tên mà kết thúc bằng “sen”. Và chỉ khi nào SQL Server thực hiện xong việc quét (scan) bảng, nó mới có thể cho ra chính xác số bản ghi đáp ứng truy vấn trên.

Một câu truy vấn khác, nếu bạn muốn tìm các bản ghi mà LastNames bao gồm chính xác sáu ký tự và sau đó là “sen”, bạn sẽ viết như thế này :

SELECT DISTINCT LastName
FROM Person.Contact
WHERE LastName LIKE '___sen’

Ở đây tôi đã sử dụng ký tự đại diện (_) để thay cho chính xác một ký tự nào đó. Một lần nữa, SQL Engine biết rằng nó phải tìm các bản ghi mà LastName được bắt đầu bằng sáu ký tự và sau đó là “sen” trong bảng Person.Contact.

SQL Server có thể trả về kết quả nhanh hơn nếu nó giới hạn được số bản ghi mà nó phải quét qua. Dưới đây là một ví dụ khi bạn muốn trả về các bản ghi LastNames bắt đầu với “A” và kết thúc bằng “sen”:

SELECT DISTINCT LastName
FROM Person.Contact
WHERE LastName LIKE 'A%sen'

Bằng cách đặt ký tự “A” phía trước dấu phần trăm (%), bạn đã giới hạn được các bản ghi mà SQL Server phải quét qua. SQL Server đủ thông minh để hiểu rằng chỉ các bản ghi nào mà phía trước có chữ “A” thì mới có thể thỏa mãn câu truy vấn trên, nó sẽ không phải quét qua các bản ghi mà LastNames không có chữ “A” đầu tiên.

Một cách khác để thực hiện truy vấn với các ký tự đại diện:

SELECT DISTINCT LastName
FROM Person.Contact
WHERE LastName LIKE '[A-M]%sen'

Trong câu lệnh trên, tôi đã thông báo cho SQL Server biết rằng nó cần phải tìm những bản ghi có LastName bắt đầu bằng một trong các ký tự từ A đến M, và có kết thúc bằng “sen”.

Chỉ sử dụng DISTINCT nếu bạn cần

Đặt mệnh đề DISTINCT vào câu lệnh SELECT của bạn sẽ giúp bạn nhận được các bản ghi duy nhất, loại bỏ các bản sao. Điều này làm cho SQL Server mất thêm một việc là sắp xếp các bản ghi nhận được để nó phát hiện và loại các bản sao y hệt nhau. Do đó, một khi bạn đã biết rằng trong kết quả sẽ không thể chứa các bản ghi y hệt nhau, thì không cần phải dùng đến DISTINCT.

Chỉ sử dụng UNION nếu bạn cần

Mệnh đề UNION loại bỏ các bản ghi trùng lặp khi nó ghép hai bộ bản ghi với nhau. Cũng giống như trong ví dụ trước, trong ví dụ này toán tử UNION đòi hỏi một hoạt động sắp xếp để SQL Server có thể loại bỏ bản sao. Nếu bạn biết chính xác rằng không thể có hai bản ghi nào hoàn toàn giống nhau thì không cần phải sử dụng UNION. Thay vào đó nếu cần ghép hai bộ bản ghi với nhau, bạn có thể sử dụng UNION ALL.

Có nhiều vấn đề để tối ưu hóa tốc độ ứng dụng, có thể là tối ưu về tốc độ truy xuất dữ liệu, tối ưu xử lý cho CPU, cho bộ nhớ, cho băng thông,… Việc viết tốt câu lệnh SQL sẽ giúp bạn tối ưu hơn tốc độ truy xuất dữ liệu, đó là cơ sở để bạn có được một ứng dụng hoạt động trơn tru và hiệu quả.

Bài viết liên quan