[Phần 1 | Phần 2 | Phần 3 | Phần 4]
MERGE
câu lệnh (được giới thiệu trong SQL Server 2008) cho phép chúng tôi thực hiện hỗn hợp INSERT
, UPDATE
và DELETE
các hoạt động sử dụng một câu lệnh duy nhất. Các vấn đề về Bảo vệ Halloween cho MERGE
chủ yếu là sự kết hợp của các yêu cầu của các hoạt động riêng lẻ, nhưng có một số khác biệt quan trọng và một số tối ưu hóa thú vị chỉ áp dụng cho MERGE
.
Tránh vấn đề Halloween với MERGE
Chúng ta bắt đầu bằng cách xem lại ví dụ Demo và Staging từ phần hai:
TẠO BẢNG dbo.Demo (SomeKey số nguyên KHÔNG NULL, CONSTRAINT PK_Demo PRIMARY KEY (SomeKey)); TẠO BẢNG dbo.Staging (số nguyên SomeKey KHÔNG NULL); CHÈN GIÁ TRỊ dbo.Staging (SomeKey) (1234), (1234); TẠO CHỈ SỐ KHÔNG ĐƯỢC ĐIỀU CHỈNH c TRÊN dbo.Staging (SomeKey); INSERT dbo.DemoSELECT s.SomeKeyFROM dbo.Staging AS sWHERE KHÔNG TỒN TẠI (CHỌN 1 TỪ dbo.Demo AS d WHERE d.SomeKey =s.SomeKey);
Như bạn có thể nhớ lại, ví dụ này được sử dụng để chỉ ra rằng một INSERT
yêu cầu Bảo vệ Halloween khi bảng mục tiêu chèn cũng được tham chiếu trong SELECT
một phần của truy vấn (EXISTS
trong trường hợp này). Hành vi đúng cho INSERT
tuyên bố ở trên là cố gắng thêm cả hai 1234 giá trị và do đó không thành công với PRIMARY KEY
sự vi phạm. Không có sự phân tách pha, INSERT
sẽ thêm sai một giá trị, hoàn thành mà không có lỗi.
Kế hoạch thực thi INSERT
Đoạn mã trên có một điểm khác biệt so với đoạn mã được sử dụng trong phần hai; một chỉ mục không hợp nhất trên bảng Staging đã được thêm vào. INSERT
kế hoạch thực hiện vẫn yêu cầu Bảo vệ Halloween mặc dù:
Kế hoạch thực thi MERGE
Bây giờ, hãy thử cùng một cách chèn logic được thể hiện bằng MERGE
cú pháp:
MERGE dbo.Demo AS dUSING dbo.Staging AS s ON s.SomeKey =d.SomeKeyWHEN KHÔNG ĐƯỢC PHÉP THEO MỤC TIÊU THÌ CHÈN (SomeKey) CÁC GIÁ TRỊ (s.SomeKey);
Trong trường hợp bạn không quen với cú pháp, logic ở đó là so sánh các hàng trong bảng Staging và Demo trên giá trị SomeKey và nếu không tìm thấy hàng phù hợp nào trong bảng đích (Demo), chúng tôi sẽ chèn một hàng mới. Điều này có ngữ nghĩa chính xác giống như INSERT...WHERE NOT EXISTS
mã, tất nhiên. Tuy nhiên, kế hoạch thực hiện khá khác nhau:
Lưu ý rằng kế hoạch này thiếu một Eager Table Spool. Mặc dù vậy, truy vấn vẫn tạo ra thông báo lỗi chính xác. Có vẻ như SQL Server đã tìm ra cách để thực thi MERGE
lập kế hoạch lặp đi lặp lại trong khi vẫn tôn trọng sự phân chia giai đoạn hợp lý theo yêu cầu của tiêu chuẩn SQL.
Tối ưu hóa việc lấp đầy lỗ
Trong các trường hợp thích hợp, trình tối ưu hóa SQL Server có thể nhận ra rằng MERGE
tuyên bố là lấp đầy lỗ , chỉ là một cách nói khác rằng câu lệnh chỉ thêm các hàng có khoảng trống hiện có trong khóa của bảng đích.
Để tối ưu hóa này được áp dụng, các giá trị được sử dụng trong WHEN NOT MATCHED BY TARGET
mệnh đề phải chính xác khớp với ON
một phần của USING
mệnh đề. Ngoài ra, bảng đích phải có một khóa duy nhất (một yêu cầu được đáp ứng bởi PRIMARY KEY
Trong trường hợp hiện tại). Khi các yêu cầu này được đáp ứng, MERGE
tuyên bố không yêu cầu bảo vệ khỏi Vấn đề Halloween.
Tất nhiên, MERGE
tuyên bố là về mặt logic không hơn không kém lấp đầy lỗ so với INSERT...WHERE NOT EXISTS
cú pháp. Sự khác biệt là trình tối ưu hóa có toàn quyền kiểm soát việc triển khai MERGE
câu lệnh, trong khi INSERT
cú pháp sẽ yêu cầu nó lý luận về ngữ nghĩa rộng hơn của truy vấn. Con người có thể dễ dàng nhận thấy rằng INSERT
cũng lấp đầy lỗ hổng, nhưng trình tối ưu hóa không nghĩ về mọi thứ theo cách chúng ta làm.
Để minh họa đối sánh chính xác yêu cầu mà tôi đã đề cập, hãy xem xét cú pháp truy vấn sau đây không hưởng lợi từ việc tối ưu hóa việc lấp đầy lỗ. Kết quả là Bảo vệ Halloween đầy đủ được cung cấp bởi Eager Table Spool:
MERGE dbo.Demo AS dUSING dbo .Staging AS s ON s.SomeKey =d.
Sự khác biệt duy nhất ở đó là phép nhân với một trong
VALUES
mệnh đề - điều gì đó không thay đổi logic của truy vấn, nhưng đủ để ngăn việc áp dụng tối ưu hóa lấp đầy lỗ hổng.Lấp lỗ bằng các vòng lặp lồng nhau
Trong ví dụ trước, trình tối ưu hóa đã chọn tham gia các bảng bằng cách sử dụng phép kết hợp Hợp nhất. Tối ưu hóa lấp đầy lỗ cũng có thể được áp dụng khi bạn chọn phép nối Các vòng lặp lồng nhau, nhưng điều này yêu cầu đảm bảo tính duy nhất bổ sung trên bảng nguồn và tìm kiếm chỉ mục ở phía bên trong của phép nối. Để xem điều này trong thực tế, chúng tôi có thể xóa dữ liệu tổ chức hiện có, thêm tính duy nhất vào chỉ mục không phân biệt và thử
MERGE
một lần nữa:- Loại bỏ các hàng trùng lặp hiện cóTRUNCATE TABLE dbo.Staging; - Chuyển đổi chỉ mục thành CHỈ SỐ KHÔNG ĐƯỢC ĐIỀU CHỈNH ĐỘC ĐÁO duy nhất c TRÊN dbo.Staging (SomeKey) WITH (DROP_EXISTING =ON); - Dữ liệu mẫuINSERT dbo.Staging (SomeKey) VALUES (1234), (5678); - Hole-fill mergeMERGE dbo.Demo AS dUSING dbo.Staging AS s ON s.SomeKey =d.Kế hoạch thực thi kết quả một lần nữa sử dụng tối ưu hóa lấp đầy lỗ để tránh Bảo vệ Halloween, sử dụng kết hợp các vòng lặp lồng nhau và tìm kiếm bên trong vào bảng mục tiêu:
Tránh duyệt chỉ mục không cần thiết
Khi áp dụng tối ưu hóa lấp đầy lỗ, động cơ cũng có thể áp dụng một tối ưu hóa khác. Nó có thể nhớ vị trí chỉ mục hiện tại trong khi đọc bảng đích (xử lý từng hàng một, hãy nhớ) và sử dụng lại thông tin đó khi thực hiện chèn, thay vì tìm kiếm b-tree để tìm vị trí chèn. Lý do là vị trí đọc hiện tại rất có thể nằm trên cùng một trang mà hàng mới sẽ được chèn vào. Việc kiểm tra xem hàng trên thực tế có thuộc về trang này không rất nhanh, vì nó chỉ bao gồm việc kiểm tra các khóa thấp nhất và cao nhất hiện được lưu trữ ở đó.
Việc kết hợp loại bỏ Bộ đệm Bảng Eager và lưu điều hướng chỉ mục trên mỗi hàng có thể mang lại lợi ích đáng kể trong khối lượng công việc OLTP, miễn là kế hoạch thực thi được truy xuất từ bộ đệm. Chi phí biên dịch cho
MERGE
các câu lệnh cao hơn so vớiINSERT
,UPDATE
vàDELETE
, vì vậy kế hoạch tái sử dụng là một cân nhắc quan trọng. Nó cũng hữu ích để đảm bảo rằng các trang có đủ không gian trống để chứa các hàng mới, tránh tình trạng tách trang. Điều này thường đạt được thông qua duy trì chỉ mục bình thường và chỉ định mộtFILLFACTOR
phù hợp .Tôi đề cập đến khối lượng công việc OLTP, thường có một số lượng lớn các thay đổi tương đối nhỏ, bởi vì
MERGE
tối ưu hóa có thể không phải là một lựa chọn tốt khi một số lượng lớn các hàng được xử lý trên mỗi câu lệnh. Các tối ưu hóa khác nhưINSERTs
được ghi nhật ký tối thiểu hiện không thể kết hợp với việc lấp lỗ. Như mọi khi, các đặc tính hiệu suất nên được đánh giá chuẩn để đảm bảo mang lại những lợi ích mong đợi.Tối ưu hóa lấp đầy lỗ cho
MERGE
chèn có thể được kết hợp với cập nhật và xóa bằng cách sử dụngMERGE
bổ sung điều khoản; từng thao tác thay đổi dữ liệu được đánh giá riêng cho Vấn đề Halloween.Tránh tham gia
Tối ưu hóa cuối cùng mà chúng tôi sẽ xem xét có thể được áp dụng khi
MERGE
câu lệnh chứa các thao tác cập nhật và xóa cũng như chèn lấp lỗ và bảng đích có một chỉ mục được phân cụm duy nhất. Ví dụ sau đây cho thấy mộtMERGE
phổ biến mẫu trong đó các hàng chưa khớp được chèn và các hàng phù hợp được cập nhật hoặc xóa tùy thuộc vào một điều kiện bổ sung:CREATE TABLE #T (col1 integer NOT NULL, col2 integer NOT NULL, CONSTRAINT PK_T PRIMARY KEY (col1)); TẠO BẢNG #S (col1 integer NOT NULL, col2 integer NOT NULL, CONSTRAINT PK_S PRIMARY KEY (col1)); CHÈN #T (col1, col2) CÁC GIÁ TRỊ (1, 50), (3, 90); CHÈN #S (col1, col2) CÁC GIÁ TRỊ (1, 40), (2, 80), (3, 90);
MERGE
tuyên bố cần thiết để thực hiện tất cả các thay đổi được yêu cầu là rất nhỏ gọn:
MERGE #T AS tUSING #S AS s ON t.col1 =s.col1 KHÔNG ĐƯỢC PHÙ HỢP KHI CHÈN CÁC GIÁ TRỊ (s.col1, s.col2) KHI ĐÃ ĐƯỢC KẾT HỢP VÀ t.col2 - s.col2 =0 THÌ ĐÃ XÓA CẬP NHẬT CÀI ĐẶT t.col2 - =s.col2;Kế hoạch thực hiện khá bất ngờ:
Không có Bảo vệ Halloween, không có liên kết giữa bảng nguồn và bảng mục tiêu và bạn sẽ không thường xuyên thấy toán tử Chèn chỉ mục theo cụm được theo sau bởi phép hợp nhất chỉ mục theo cụm vào cùng một bảng. Đây là một cách tối ưu hóa khác được nhắm mục tiêu vào khối lượng công việc OLTP với khả năng tái sử dụng kế hoạch cao và lập chỉ mục phù hợp.
Ý tưởng là đọc một hàng từ bảng nguồn và ngay lập tức cố gắng chèn nó vào mục tiêu. Nếu vi phạm chính dẫn đến lỗi sẽ bị loại bỏ, toán tử Chèn sẽ xuất ra hàng xung đột mà nó tìm thấy và sau đó hàng đó được xử lý cho thao tác cập nhật hoặc xóa bằng cách sử dụng toán tử Kế hoạch hợp nhất như bình thường.
Nếu lần chèn gốc thành công (không có vi phạm khóa) thì quá trình xử lý tiếp tục với hàng tiếp theo từ nguồn (toán tử Hợp nhất chỉ xử lý cập nhật và xóa). Tối ưu hóa này chủ yếu mang lại lợi ích cho
MERGE
các truy vấn trong đó hầu hết các hàng nguồn dẫn đến một phần chèn. Một lần nữa, cần phải đo điểm chuẩn cẩn thận để đảm bảo hiệu suất tốt hơn so với việc sử dụng các câu lệnh riêng biệt.Tóm tắt
MERGE
tuyên bố cung cấp một số cơ hội tối ưu hóa duy nhất. Trong những trường hợp phù hợp, nó có thể tránh được sự cần thiết phải thêm Bảo vệ Halloween rõ ràng so vớiINSERT
tương đương hoạt động, hoặc thậm chí có thể là sự kết hợp củaINSERT
,UPDATE
vàDELETE
các câu lệnh.MERGE
bổ sung -các tối ưu hóa cụ thể có thể tránh việc duyệt qua b-cây chỉ mục thường cần thiết để xác định vị trí chèn cho một hàng mới và cũng có thể tránh hoàn toàn nhu cầu kết hợp bảng nguồn và bảng đích.Trong phần cuối cùng của loạt bài này, chúng ta sẽ xem xét lý do của trình tối ưu hóa truy vấn về nhu cầu bảo vệ Halloween và xác định thêm một số thủ thuật mà nó có thể sử dụng để tránh phải thêm Eager Table Spools vào các kế hoạch thực thi thay đổi dữ liệu.
[Phần 1 | Phần 2 | Phần 3 | Phần 4]