SQL Server luôn sử dụng tổ hợp toán tử Tách, Sắp xếp và Thu gọn khi duy trì một chỉ mục duy nhất như là một phần của bản cập nhật ảnh hưởng (hoặc có thể ảnh hưởng) nhiều hơn một hàng.
Làm việc qua ví dụ trong câu hỏi, chúng ta có thể viết bản cập nhật dưới dạng một bản cập nhật một hàng riêng biệt cho mỗi trong bốn hàng có mặt:
-- Per row updates
UPDATE dbo.Banana SET pk = 2 WHERE pk = 1;
UPDATE dbo.Banana SET pk = 3 WHERE pk = 2;
UPDATE dbo.Banana SET pk = 4 WHERE pk = 3;
UPDATE dbo.Banana SET pk = 5 WHERE pk = 4;
Vấn đề là câu lệnh đầu tiên sẽ thất bại, vì nó thay đổi pk
từ 1 thành 2 và đã có một hàng trong đó pk
= 2. Công cụ lưu trữ SQL Server yêu cầu các chỉ mục duy nhất vẫn duy nhất ở mỗi giai đoạn xử lý, ngay cả trong một câu lệnh . Đây là vấn đề được giải quyết bằng Tách, Sắp xếp và Thu gọn.
Tách
Bước đầu tiên là phân tách từng câu lệnh cập nhật thành một lần xóa và sau đó là chèn:
DELETE dbo.Banana WHERE pk = 1;
INSERT dbo.Banana (pk, c1, c2) VALUES (2, 'A', 'W');
DELETE dbo.Banana WHERE pk = 2;
INSERT dbo.Banana (pk, c1, c2) VALUES (3, 'B', 'X');
DELETE dbo.Banana WHERE pk = 3;
INSERT dbo.Banana (pk, c1, c2) VALUES (4, 'C', 'Y');
DELETE dbo.Banana WHERE pk = 4;
INSERT dbo.Banana (pk, c1, c2) VALUES (5, 'D', 'Z');
Toán tử Split thêm một cột mã hành động vào luồng (ở đây có nhãn Act1007):
Mã hành động là 1 cho một bản cập nhật, 3 cho một lần xóa và 4 cho một lần chèn.
Sắp xếp
Các câu lệnh phân tách ở trên vẫn sẽ tạo ra một vi phạm khóa duy nhất tạm thời sai, vì vậy bước tiếp theo là sắp xếp các câu lệnh theo các khóa của chỉ mục duy nhất được cập nhật ( pk
trong trường hợp này), sau đó theo mã hành động. Trong ví dụ này, điều này chỉ có nghĩa là xóa (3) trên cùng một khóa được sắp xếp trước khi chèn (4). Thứ tự kết quả là:
-- Sort (pk, action)
DELETE dbo.Banana WHERE pk = 1;
DELETE dbo.Banana WHERE pk = 2;
INSERT dbo.Banana (pk, c1, c2) VALUES (2, 'A', 'W');
DELETE dbo.Banana WHERE pk = 3;
INSERT dbo.Banana (pk, c1, c2) VALUES (3, 'B', 'X');
DELETE dbo.Banana WHERE pk = 4;
INSERT dbo.Banana (pk, c1, c2) VALUES (4, 'C', 'Y');
INSERT dbo.Banana (pk, c1, c2) VALUES (5, 'D', 'Z');
Sự sụp đổ
Giai đoạn trước là đủ để đảm bảo tránh các vi phạm duy nhất sai trong mọi trường hợp. Để tối ưu hóa, Thu gọn kết hợp xóa và chèn liền kề trên cùng một giá trị khóa vào một bản cập nhật:
-- Collapse (pk)
DELETE dbo.Banana WHERE pk = 1;
UPDATE dbo.Banana SET c1 = 'A', c2 = 'W' WHERE pk = 2;
UPDATE dbo.Banana SET c1 = 'B', c2 = 'X' WHERE pk = 3;
UPDATE dbo.Banana SET c1 = 'C', c2 = 'Y' WHERE pk = 4;
INSERT dbo.Banana (pk, c1, c2) VALUES (5, 'D', 'Z');
Các cặp xóa / chèn cho pk
các giá trị 2, 3 và 4 đã được kết hợp thành một bản cập nhật, để lại một lần xóa trên pk
= 1 và chèn cho pk
= 5.
Toán tử Thu gọn nhóm các hàng theo các cột chính và cập nhật mã hành động để phản ánh kết quả thu gọn:
Cập nhật chỉ mục cụm
Toán tử này được gắn nhãn là Cập nhật, nhưng nó có khả năng chèn, cập nhật và xóa. Hành động nào được thực hiện bởi Cập nhật chỉ mục cụm trên mỗi hàng được xác định bởi giá trị của mã hành động trong hàng đó. Toán tử có thuộc tính Action để phản ánh chế độ hoạt động này:
Quầy sửa đổi hàng
Lưu ý rằng ba bản cập nhật ở trên không sửa đổi (các) khóa của chỉ mục duy nhất đang được duy trì. Trên thực tế, chúng tôi đã chuyển đổi các bản cập nhật cho các cột chính trong chỉ mục thành các bản cập nhật của các cột không khóa ( c1
và c2
), cộng với xóa và chèn. Không phải xóa hay chèn đều có thể gây ra vi phạm khóa duy nhất sai.
Một chèn hoặc xóa ảnh hưởng đến mỗi cột duy nhất trong hàng, do đó, số liệu thống kê được liên kết với mỗi cột sẽ tăng các bộ đếm sửa đổi của chúng. Đối với (các) bản cập nhật, chỉ các số liệu thống kê với bất kỳ cột nào được cập nhật làm cột hàng đầu có các bộ đếm sửa đổi của chúng tăng lên (ngay cả khi giá trị không thay đổi).
Do đó, bộ đếm sửa đổi hàng thống kê hiển thị 2 thay đổi pk
và 5 cho c1
và c2
:
-- Collapse (pk)
DELETE dbo.Banana WHERE pk = 1; -- All columns modified
UPDATE dbo.Banana SET c1 = 'A', c2 = 'W' WHERE pk = 2; -- c1 and c2 modified
UPDATE dbo.Banana SET c1 = 'B', c2 = 'X' WHERE pk = 3; -- c1 and c2 modified
UPDATE dbo.Banana SET c1 = 'C', c2 = 'Y' WHERE pk = 4; -- c1 and c2 modified
INSERT dbo.Banana (pk, c1, c2) VALUES (5, 'D', 'Z'); -- All columns modified
Lưu ý: Chỉ những thay đổi được áp dụng cho đối tượng cơ sở (chỉ số heap hoặc cụm) mới ảnh hưởng đến các bộ đếm sửa đổi hàng thống kê. Các chỉ mục không phân cụm là các cấu trúc thứ cấp, phản ánh các thay đổi đã được thực hiện cho đối tượng cơ sở. Chúng hoàn toàn không ảnh hưởng đến các quầy sửa đổi hàng thống kê.
Nếu một đối tượng có nhiều chỉ mục duy nhất, một tổ hợp Tách, Sắp xếp, Thu gọn riêng biệt được sử dụng để tổ chức các bản cập nhật cho từng chỉ mục. SQL Server tối ưu hóa trường hợp này cho các chỉ mục không bao gồm bằng cách lưu kết quả của Spool vào Spool Table Spool, sau đó phát lại tập hợp đó cho từng chỉ mục duy nhất (sẽ có Sắp xếp riêng theo khóa chỉ mục + mã hành động và Thu gọn).
Ảnh hưởng đến cập nhật thống kê
Cập nhật thống kê tự động (nếu được bật) xảy ra khi trình tối ưu hóa truy vấn cần thông tin thống kê và thông báo rằng số liệu thống kê hiện tại đã lỗi thời (hoặc không hợp lệ do thay đổi lược đồ). Thống kê được coi là lỗi thời khi số lượng sửa đổi được ghi vượt quá ngưỡng.
Sắp xếp Tách / Sắp xếp / Thu gọn dẫn đến các sửa đổi hàng khác nhau được ghi lại hơn mong đợi. Điều này, đến lượt nó, có nghĩa là một bản cập nhật thống kê có thể được kích hoạt sớm hơn hoặc muộn hơn so với trường hợp khác.
Trong ví dụ trên, sửa đổi hàng cho cột khóa tăng thêm 2 (thay đổi ròng) thay vì 4 (một cho mỗi hàng của bảng bị ảnh hưởng) hoặc 5 (một cho mỗi lần xóa / cập nhật / chèn được tạo bởi Thu gọn).
Ngoài ra, các cột không khóa không bị thay đổi về mặt logic bởi truy vấn ban đầu sẽ tích lũy các sửa đổi hàng, có thể đánh số gấp đôi số hàng của bảng được cập nhật (một cho mỗi lần xóa và một cho mỗi lần chèn).
Số lượng thay đổi được ghi lại tùy thuộc vào mức độ chồng chéo giữa các giá trị cột khóa cũ và mới (và do đó mức độ xóa và chèn riêng biệt có thể được thu gọn). Đặt lại bảng giữa mỗi lần thực hiện, các truy vấn sau đây cho thấy hiệu ứng trên các bộ đếm sửa đổi hàng với các lớp phủ khác nhau:
UPDATE dbo.Banana SET pk = pk + 0; -- Full overlap
UPDATE dbo.Banana SET pk = pk + 1;
UPDATE dbo.Banana SET pk = pk + 2;
UPDATE dbo.Banana SET pk = pk + 3;
UPDATE dbo.Banana SET pk = pk + 4; -- No overlap