Tại sao lần thứ hai tôi cố gắng hợp nhất cùng một hàng đã được chèn, nó lại dẫn đến một lỗi. Nếu hàng này vượt quá kích thước hàng tối đa, nó sẽ không thể chèn nó ở vị trí đầu tiên.
Đầu tiên, cảm ơn bạn cho kịch bản sinh sản.
Vấn đề không phải là SQL Server không thể chèn hoặc cập nhật một hàng người dùng cụ thể . Như bạn đã lưu ý, một hàng đã được chèn vào bảng chắc chắn không thể quá lớn về cơ bản để SQL Server xử lý.
Sự cố xảy ra do việc MERGE
triển khai SQL Server thêm thông tin được tính toán (dưới dạng các cột bổ sung) trong các bước trung gian trong kế hoạch thực hiện. Thông tin bổ sung này là cần thiết vì lý do kỹ thuật, để theo dõi xem mỗi hàng sẽ dẫn đến chèn, cập nhật hoặc xóa; và cũng liên quan đến cách SQL Server thường tránh các vi phạm khóa tạm thời trong quá trình thay đổi chỉ mục.
Công cụ lưu trữ máy chủ SQL yêu cầu các chỉ mục phải là duy nhất (bên trong, bao gồm mọi trình duy nhất ẩn) mọi lúc - vì mỗi hàng được xử lý - thay vì ở đầu và cuối của giao dịch hoàn chỉnh. Trong các MERGE
trường hợp phức tạp hơn , điều này đòi hỏi phải phân tách (chuyển đổi bản cập nhật thành xóa và chèn riêng), Sắp xếp và Thu gọn tùy chọn (biến các phần chèn và cập nhật liền kề trên cùng một khóa thành bản cập nhật). Thêm thông tin .
Bên cạnh đó, lưu ý rằng vấn đề không xảy ra nếu bảng mục tiêu là một đống (bỏ chỉ mục cụm để thấy điều này). Tôi không khuyến nghị đây là cách khắc phục, chỉ đề cập đến nó để làm nổi bật mối liên hệ giữa việc duy trì tính duy nhất của chỉ số mọi lúc (được nhóm trong trường hợp hiện tại) và Phân tách-Thu gọn.
Trong các truy vấn đơn giản MERGE
, với các chỉ mục duy nhất phù hợp và mối quan hệ đơn giản giữa các hàng nguồn và đích (thường khớp với một ON
mệnh đề có tất cả các cột chính), trình tối ưu hóa truy vấn có thể đơn giản hóa phần lớn logic chung, dẫn đến các kế hoạch tương đối đơn giản không yêu cầu Dự án phân tách-thu gọn hoặc thu hẹp phân đoạn để kiểm tra các hàng mục tiêu chỉ được chạm một lần.
Trong các MERGE
truy vấn phức tạp , với logic mờ hơn, trình tối ưu hóa thường không thể áp dụng các đơn giản hóa này, cho thấy nhiều logic cơ bản phức tạp hơn cần thiết để xử lý chính xác (lỗi sản phẩm và có rất nhiều ).
Truy vấn của bạn chắc chắn đủ điều kiện là phức tạp. Các ON
điều khoản không phù hợp với các phím số (và tôi hiểu tại sao), và 'bảng nguồn' là một tự join liên quan đến một chức năng cửa sổ bảng xếp hạng (một lần nữa, với lý do):
MERGE MERGE_REPRO_TARGET AS targetTable
USING
(
SELECT * FROM
(
SELECT
*,
ROW_NUMBER() OVER (
PARTITION BY ww,id, tenant
ORDER BY
(
SELECT COUNT(1)
FROM MERGE_REPRO_SOURCE AS targetTable
WHERE
targetTable.[ibi_bulk_id] = sourceTable.[ibi_bulk_id]
AND targetTable.[ibi_row_id] <> sourceTable.[ibi_row_id]
AND
(
(targetTable.[ww] = sourceTable.[ww])
AND (targetTable.[id] = sourceTable.[id])
AND (targetTable.[tenant] = sourceTable.[tenant])
)
AND NOT ((targetTable.[sampletime] <= sourceTable.[sampletime]))
),
sourceTable.ibi_row_id DESC
) AS idx
FROM MERGE_REPRO_SOURCE sourceTable
WHERE [ibi_bulk_id] in (20150803110418887)
) AS bulkData
where idx = 1
) AS sourceTable
ON
(targetTable.[ww] = sourceTable.[ww])
AND (targetTable.[id] = sourceTable.[id])
AND (targetTable.[tenant] = sourceTable.[tenant])
...
Điều này dẫn đến nhiều cột được tính toán thêm, chủ yếu được liên kết với Tách và dữ liệu cần thiết khi một bản cập nhật được chuyển đổi thành cặp chèn / cập nhật. Các cột bổ sung này dẫn đến một hàng trung gian vượt quá 8060 byte được phép tại Sắp xếp trước đó - cột chỉ sau Bộ lọc:
Lưu ý rằng Bộ lọc có 1.319 cột (biểu thức và cột cơ sở) trong Danh sách đầu ra. Đính kèm trình gỡ lỗi cho thấy ngăn xếp cuộc gọi tại điểm ngoại lệ nghiêm trọng được nêu ra:
Lưu ý khi thông qua rằng vấn đề không nằm ở Spool - ngoại lệ được chuyển thành cảnh báo về tiềm năng cho một hàng quá lớn.
Tại sao cập nhật bằng cách sử dụng hợp nhất không thành công, trong khi chèn thì và cập nhật trực tiếp cũng không?
Một bản cập nhật trực tiếp không có độ phức tạp bên trong giống như MERGE
. Đây là một hoạt động đơn giản hơn về cơ bản có xu hướng đơn giản hóa và tối ưu hóa tốt hơn. Xóa NOT MATCHED
mệnh đề cũng có thể loại bỏ đủ độ phức tạp sao cho lỗi không được tạo ra trong một số trường hợp. Điều đó không xảy ra với repro, tuy nhiên.
Cuối cùng, lời khuyên của tôi là tránh MERGE
những nhiệm vụ lớn hơn hoặc phức tạp hơn. Kinh nghiệm của tôi là các câu lệnh chèn / cập nhật / xóa riêng biệt có xu hướng tối ưu hóa tốt hơn, dễ hiểu hơn và cũng thường thực hiện tốt hơn về tổng thể, so với MERGE
.