Trong quá trình biên dịch và thực thi truy vấn, SQL Server không dành thời gian để tìm hiểu xem câu lệnh UPDATE có thực sự thay đổi bất kỳ giá trị nào hay không. Nó chỉ thực hiện ghi như mong đợi, ngay cả khi không cần thiết.
Trong trường hợp như
update table1 set col1 = 'hello'
bạn có thể nghĩ rằng SQL sẽ không làm được gì, nhưng nó sẽ - nó sẽ thực hiện tất cả các thao tác ghi cần thiết như thể bạn thực sự thay đổi giá trị. Điều này xảy ra cho cả bảng vật lý (hoặc chỉ mục được phân cụm) cũng như bất kỳ chỉ mục không phân cụm nào được xác định trên cột đó. Điều này gây ra việc ghi vào các bảng / chỉ mục vật lý, tính toán lại các chỉ mục và ghi nhật ký giao dịch. Khi làm việc với các tập dữ liệu lớn, sẽ có những lợi ích lớn về hiệu suất khi chỉ cập nhật các hàng sẽ nhận được thay đổi.
Nếu chúng ta muốn tránh chi phí của những lần ghi này khi không cần thiết, chúng ta phải nghĩ ra một cách để kiểm tra xem có cần cập nhật hay không. Một cách để kiểm tra nhu cầu cập nhật là thêm một cái gì đó như “where col <> 'hello'.
update table1 set col1 = 'hello' where col1 <> 'hello'
Nhưng điều này sẽ không hoạt động tốt trong một số trường hợp, ví dụ:nếu bạn đang cập nhật nhiều cột trong bảng có nhiều hàng và chỉ một tập hợp con nhỏ của những hàng đó thực sự bị thay đổi giá trị. Điều này là do nhu cầu sau đó lọc trên tất cả các cột đó và các vị từ không bình đẳng thường không thể sử dụng tìm kiếm chỉ mục và chi phí ghi bảng &chỉ mục cũng như các mục nhập nhật ký giao dịch như đã đề cập ở trên.
Nhưng có một cách thay thế tốt hơn nhiều bằng cách sử dụng kết hợp mệnh đề EXISTS với mệnh đề EXCEPT. Ý tưởng là so sánh các giá trị trong hàng đích với các giá trị trong hàng nguồn phù hợp để xác định xem có thực sự cần cập nhật hay không. Hãy xem truy vấn đã sửa đổi bên dưới và kiểm tra bộ lọc truy vấn bổ sung bắt đầu bằng EXISTS. Lưu ý rằng bên trong mệnh đề EXISTS, các câu lệnh SELECT không có mệnh đề FROM. Phần đó đặc biệt quan trọng vì điều này chỉ thêm vào một lần quét liên tục bổ sung và một hoạt động lọc trong kế hoạch truy vấn (chi phí của cả hai là nhỏ). Vì vậy, những gì bạn kết thúc là một phương pháp rất gọn nhẹ để xác định xem liệu CẬP NHẬT có cần thiết ngay từ đầu hay không, tránh việc ghi thêm chi phí không cần thiết.
update table1 set col1 = 'hello'
/* AVOID NET ZERO CHANGES */
where exists
(
/* DESTINATION */
select table1.col1
except
/* SOURCE */
select col1 = 'hello'
)
Điều này trông quá phức tạp so với việc kiểm tra các bản cập nhật trong mệnh đề WHERE đơn giản cho trường hợp đơn giản trong câu hỏi ban đầu khi bạn đang cập nhật một giá trị cho tất cả các hàng trong bảng có giá trị theo nghĩa đen. Tuy nhiên, kỹ thuật này hoạt động rất tốt nếu bạn đang cập nhật nhiều cột trong một bảng và nguồn cập nhật của bạn là một truy vấn khác và bạn muốn giảm thiểu các mục ghi và nhật ký giao dịch. Nó cũng hoạt động tốt hơn so với việc kiểm tra mọi trường với <>.
Một ví dụ đầy đủ hơn có thể là
update table1
set col1 = 'hello',
col2 = 'hello',
col3 = 'hello'
/* Only update rows from CustomerId 100, 101, 102 & 103 */
where table1.CustomerId IN (100, 101, 102, 103)
/* AVOID NET ZERO CHANGES */
and exists
(
/* DESTINATION */
select table1.col1
table1.col2
table1.col3
except
/* SOURCE */
select z.col1,
z.col2,
z.col3
from #anytemptableorsubquery z
where z.CustomerId = table1.CustomerId
)