Mở đầu
SQL performance tuning là một nhiệm vụ cực kỳ khó khăn, đặc biệt là khi làm việc với dữ liệu lớn. Ở đó ngay cả một thay đổi nhỏ nhất cũng có thể có tác động mạnh mẽ (tích cực hoặc tiêu cực) đến performance.
SELECT là một trong những câu lệnh quen thuộc mà bất cứ ai có tìm hiểu về SQL đề sẽ biết, tuy nhiên biết thì chưa hẳn là đã thực sự hiểu về nó. Trong bài viết này chúng ta sẽ cùng nhau tìm hiểu sâu hơn về SQL SELECT. So sánh sự khác nhau giữa SELECT * và SELECT 1 column. Không dài dòng nữa, bắt đầu thôi nào!
P/S: Ở bài viết này, mình sẽ đề cập đến một số khái niệm trong SQL performance tuning như execution plan
, explain
. Tuy nhiên mình sẽ không đi sâu vào giải thích những khái niệm này mà sẽ giải thích ở một bài viết khác. Mọi người hãy đón chờ nha!
SELECT * và SELECT 1 column có thực sự khác nhau?
Quá dễ! SELECT * thì trả về toàn bộ column của table. Còn SELECT 1 column thì sẽ trả về duy nhất 1 column được viết tên sau lệnh SELECT.
Đúng, nhưng chưa đủ. Còn về performance thì sao?
Do SELECT * trả về nhiều column hơn SELECT 1 column. Nên đương nhiên SELECT 1 column sẽ có performance tốt hơn rồi. Thế mà cũng phải hỏi…
Đúng, với SELECT * thì lượng dữ liệu trả về sẽ nhiều hơn SELECT 1 column. Do đó thời gian lấy kết quả của database sẽ lâu hơn. Nhưng đây chỉ là 1 yếu tố nhỏ nếu chúng ta nói về SQL performance. Yếu tố chính để đánh giá performance của một câu lệnh SELECT là execution plan của câu lệnh đó.
Execution plan đối với SELECT * và SELECT 1 column
Một lưu ý nhỏ trước khi bắt đầu. Nếu một câu lệnh có execution plan với cost càng nhỏ thì câu lệnh đó càng tối ưu về performance và ngược lại.
Ở đây mình sẽ sử dụng database là PostgreSql
và pgadmin
để thực hiện đánh giá execution plan.
Mình có một table tracked_indicator
với 20k records và 16 column như hình bên dưới.
Đầu tiên mình sẽ kiểm tra execution plan của 2 câu lệnh.
Cả 2 câu lệnh SELECT đều có execution plan là sequence scan và cost là 996.63.
Cost càng nhỏ thì câu lệnh càng tối ưu. Vậy SELECT * và SELECT name có cost bằng nhau thì 2 câu lệnh này là như nhau à?
hmm…, cũng đúng. Chả nhẽ SELECT * và SELECT 1 column lại có performance như nhau….Gượm đã, bình thường có mấy khi SELECT
mà lại không có điều kiện WHERE
đâu, phải thử lại mới được.
Tiếp theo mình sẽ thực hiên SELECT
với điều kiện WHERE
trên column data_capture_frequency
Giống như vừa này, cả 2 câu lệnh đều có execution plan là sequence scan với cost là 1018.79 giống nhau. Vô lý thật, chả nhẽ SELECT * mà lại có performance ngang SELECT 1 column…. À đúng rồi, đã có điều kiện WHERE
thì phải có index
nữa chứ, thử lại lần nữa nào.
Tiếp tục là tạo index
trên column data_capture_frequency
. Sau đó thực hiện SELECT
với điều kiện WHERE
cũng trên colum data_capture_frequency
Đây rồi, cuối cùng cũng đã có sự khác biệt. Câu lệnh SELECT data_capture_frequency
có execution plan là Index Only Scan
và cost là 121.15. Trong khi đó, câu lệnh SELECT *
lại là Bitmap Heap Scan
với cost cao hơn nhiều: 846.15.
Vây là SELECT * có performance kém hơn SELECT 1 column trong trường hợp có điều kiện WHERE và có index. Nhưng vì sao nhỉ? Thế nếu SELECT 2, 3 column thôi thì sao?
Tiếp tục thử nghiệm với câu lệnh SELECT 2 column name
và data_capture_frequency
Không phải là Index Only Scan
mà là Bitmap Heap Scan
với cost 846.15 tương tự như SELECT *. Thế nếu SELECT 1 column nhưng column đó lại không nằm trong index thì sao nhỉ?
Vẫn là Bitmap Heap Scan
. Đến đây, chúng ta có thể đưa ra một kết luận là nếu câu lệnh SELECT có chứa column không thuộc điều kiện WHERE và không được đánh index thì sẽ có performance thấp hơn việc SELECT các column nằm trong điều kiện WHERE và có index
Vậy thì lý do là gì? Lý do ở đây là vì đối với câu lệnh SELECT những column nằm trong index thì database chỉ việc thực hiện index scan. Và trả lại kết quả luôn vì trong index đã có value của nhưng column đó. Tuy nhiên đối với câu lệnh SELECT những column không nằm trong index thì database ngoài việc thực hiện index scan thì phải look up qua table chính để có thể lấy được value của những column đó do không có value trong index.
Tổng kết
Trên đây là toàn bộ phần chia sẻ của mình, hi vọng rằng bài viết này sẽ giúp mọi người hiểu rõ hơn về câu lệnh SELECT trong SQL. Do mình chỉ mới nhập môn SQL Performance tuning gần đây nên có thể còn vẫn sai sót trong quá trình viết bài. Mọi người đừng ngần ngại mà để ngay comment phản hồi ở bên dưới bài viết nếu phát hiện ra sai sót nào nha. Cảm ơn và hẹn gặp lại mọi người trong những bài viết sau. See ya!
Tham khảo thêm về SQL Performance tuning ở đây