Tôi sắp phải viết lại một số mã khá cũ bằng lệnh của SQL Server BULK INSERT
vì lược đồ đã thay đổi và tôi nghĩ rằng có lẽ tôi nên nghĩ đến việc chuyển sang một thủ tục được lưu trữ với TVP thay thế, nhưng tôi đang tự hỏi tác dụng nó có thể có hiệu suất.
Một số thông tin cơ bản có thể giúp giải thích lý do tại sao tôi hỏi câu hỏi này:
Dữ liệu thực sự đến thông qua một dịch vụ web. Dịch vụ web ghi một tệp văn bản vào một thư mục chia sẻ trên máy chủ cơ sở dữ liệu, đến lượt nó thực hiện một
BULK INSERT
. Quá trình này ban đầu được triển khai trên SQL Server 2000 và tại thời điểm đó, thực sự không có giải pháp thay thế nào khác ngoài việc ghim vài trămINSERT
câu lệnh tại máy chủ, đây thực sự là quá trình ban đầu và là một thảm họa về hiệu suất.Dữ liệu được chèn hàng loạt vào một bảng dàn cố định và sau đó được hợp nhất vào một bảng lớn hơn nhiều (sau đó nó bị xóa khỏi bảng dàn).
Số lượng dữ liệu cần chèn là "lớn", nhưng không "khổng lồ" - thường là vài trăm hàng, có thể là 5-10 nghìn hàng trong một số trường hợp hiếm hoi. Vì vậy, cảm giác ruột của tôi là
BULK INSERT
hoạt động không ghi nhật ký sẽ không tạo ra sự khác biệt lớn như vậy (nhưng tất nhiên tôi không chắc chắn, do đó câu hỏi).Việc chèn thực sự là một phần của quy trình hàng loạt có đường ống lớn hơn nhiều và cần phải diễn ra nhiều lần liên tiếp; do đó hiệu suất là rất quan trọng.
Những lý do tôi muốn thay thế BULK INSERT
bằng TVP là:
Việc ghi tệp văn bản qua NetBIOS có lẽ đã tốn một khoảng thời gian và nó khá khủng khiếp từ góc độ kiến trúc.
Tôi tin rằng bảng dàn dựng có thể (và nên) bị loại bỏ. Lý do chính là dữ liệu được chèn vào cần được sử dụng cho một vài bản cập nhật khác cùng lúc với việc chèn và cố gắng cập nhật từ bảng sản xuất lớn sẽ tốn kém hơn nhiều so với việc sử dụng một dàn gần như trống rỗng bàn. Với TVP, tham số về cơ bản là bảng dàn, tôi có thể làm bất cứ điều gì tôi muốn với nó trước / sau khi chèn chính.
Tôi có thể làm được nhiều việc với kiểm tra dupe, mã dọn dẹp và tất cả chi phí liên quan đến chèn hàng loạt.
Không cần phải lo lắng về việc khóa tranh chấp trên bảng dàn hoặc tempdb nếu máy chủ nhận được một vài giao dịch này cùng một lúc (chúng tôi cố gắng tránh điều đó, nhưng nó vẫn xảy ra).
Rõ ràng là tôi sẽ lập hồ sơ về vấn đề này trước khi đưa bất cứ thứ gì vào sản xuất, nhưng tôi nghĩ có thể là ý kiến hay khi hỏi trước khi dành toàn bộ thời gian đó, xem có ai có bất kỳ cảnh báo nghiêm khắc nào về việc sử dụng TVP cho mục đích này không.
Vì vậy - đối với bất kỳ ai đủ nhiệt tình với SQL Server 2008 đã thử hoặc ít nhất là điều tra điều này, thì phán quyết là gì? Đối với các trường hợp chèn, giả sử, vài trăm đến vài nghìn hàng, xảy ra khá thường xuyên, các TVP có cắt cải không? Có sự khác biệt đáng kể về hiệu suất so với chèn số lượng lớn không?
Cập nhật: Bây giờ với ít hơn 92% dấu hỏi!
(AKA: Kết quả kiểm tra)
Kết quả cuối cùng bây giờ là trong quá trình sản xuất sau một quá trình triển khai 36 giai đoạn. Cả hai giải pháp đã được thử nghiệm rộng rãi:
- Xé ra mã thư mục chia sẻ và sử dụng
SqlBulkCopy
lớp học trực tiếp; - Chuyển sang Quy trình đã Lưu trữ với TVP.
Để người đọc có thể biết chính xác những gì đã được kiểm tra, để giảm bớt bất kỳ nghi ngờ nào về độ tin cậy của dữ liệu này, đây là giải thích chi tiết hơn về những gì quá trình nhập này thực sự làm :
Bắt đầu với một chuỗi dữ liệu tạm thời thường là khoảng 20-50 điểm dữ liệu (mặc dù đôi khi có thể lên đến vài trăm);
Thực hiện một loạt các xử lý điên rồ trên nó hầu như độc lập với cơ sở dữ liệu. Quá trình này diễn ra song song, do đó, khoảng 8-10 trình tự trong (1) đang được xử lý cùng một lúc. Mỗi quá trình song song tạo ra 3 chuỗi bổ sung.
Lấy tất cả 3 trình tự và trình tự ban đầu và kết hợp chúng thành một lô.
Kết hợp các lô từ tất cả 8-10 tác vụ xử lý hiện đã hoàn thành thành một siêu lô lớn.
Nhập nó bằng cách sử dụng
BULK INSERT
chiến lược (xem bước tiếp theo) hoặc chiến lược TVP (chuyển sang bước 8).Sử dụng
SqlBulkCopy
lớp để kết xuất toàn bộ siêu lô vào 4 bảng dàn cố định.Chạy Thủ tục đã lưu trữ (a) thực hiện một loạt các bước tổng hợp trên 2 trong số các bảng, bao gồm một số
JOIN
điều kiện, và sau đó (b) thực hiện aMERGE
trên 6 bảng sản xuất bằng cách sử dụng cả dữ liệu tổng hợp và không tổng hợp. (Đã kết thúc)HOẶC LÀ
Tạo 4
DataTable
đối tượng chứa dữ liệu được hợp nhất; 3 trong số đó chứa các loại CLR không được hỗ trợ đúng cách bởi ADO.NET TVP, vì vậy chúng phải được đưa vào dưới dạng biểu diễn chuỗi, điều này làm ảnh hưởng đến hiệu suất một chút.Cung cấp các TVP vào một Quy trình đã lưu trữ, về cơ bản thực hiện cùng một quy trình xử lý như (7), nhưng trực tiếp với các bảng đã nhận. (Đã kết thúc)
Các kết quả gần nhau một cách hợp lý, nhưng phương pháp TVP cuối cùng hoạt động trung bình tốt hơn, ngay cả khi dữ liệu vượt quá 1000 hàng một lượng nhỏ.
Lưu ý rằng quá trình nhập này được chạy nhiều nghìn lần liên tiếp, vì vậy rất dễ dàng để có được thời gian trung bình chỉ đơn giản bằng cách đếm xem đã mất bao nhiêu giờ (vâng, giờ) để hoàn thành tất cả các hợp nhất.
Ban đầu, một quá trình hợp nhất trung bình mất gần đúng 8 giây để hoàn thành (trong điều kiện tải bình thường). Loại bỏ k bùn NetBIOS và chuyển sang SqlBulkCopy
giảm thời gian xuống gần chính xác 7 giây. Việc chuyển sang TVP tiếp tục giảm thời gian xuống còn 5,2 giây mỗi đợt. Đó là sự cải thiện 35% về thông lượng cho một quy trình có thời gian chạy được tính bằng giờ - vì vậy không tệ chút nào. Nó cũng được cải thiện ~ 25% SqlBulkCopy
.
Tôi thực sự khá tự tin rằng sự cải thiện thực sự còn nhiều hơn thế này. Trong quá trình thử nghiệm, rõ ràng là sự hợp nhất cuối cùng không còn là đường dẫn quan trọng nữa; thay vào đó, Dịch vụ Web đang thực hiện tất cả quá trình xử lý dữ liệu đang bắt đầu bị giới hạn bởi số lượng yêu cầu đến. Cả CPU và I / O cơ sở dữ liệu đều không thực sự hoạt động tối đa và không có hoạt động khóa đáng kể nào. Trong một số trường hợp, chúng tôi thấy khoảng cách một vài giây nhàn rỗi giữa các lần hợp nhất liên tiếp. Có một khoảng cách nhỏ, nhưng nhỏ hơn nhiều (nửa giây hoặc lâu hơn) khi sử dụng SqlBulkCopy
. Nhưng tôi cho rằng điều đó sẽ trở thành một câu chuyện cho một ngày khác.
Kết luận: Các tham số được định giá bằng bảng thực sự hoạt động tốt hơn các BULK INSERT
hoạt động đối với các quy trình nhập + chuyển đổi phức tạp hoạt động trên các tập dữ liệu cỡ trung bình.
Tôi muốn nói thêm một điểm khác, chỉ để xoa dịu bất kỳ sự e ngại nào của một bộ phận những người là chuyên gia về bàn dàn dựng. Theo một cách nào đó, toàn bộ dịch vụ này là một quá trình dàn dựng khổng lồ. Mỗi bước của quy trình đều được kiểm tra kỹ lưỡng, vì vậy chúng tôi không cần một bảng phân tích để xác định lý do tại sao một số hợp nhất cụ thể không thành công (mặc dù trong thực tế, điều này hầu như không bao giờ xảy ra). Tất cả những gì chúng ta phải làm là đặt một cờ gỡ lỗi trong dịch vụ và nó sẽ phá vỡ trình gỡ lỗi hoặc kết xuất dữ liệu của nó vào một tệp thay vì cơ sở dữ liệu.
Nói cách khác, chúng ta đã có quá đủ cái nhìn sâu sắc về quy trình và không cần đến sự an toàn của một bảng dàn dựng; lý do duy nhất mà chúng tôi có bảng dàn dựng ngay từ đầu là để tránh làm hỏng tất cả các câu lệnh INSERT
và UPDATE
mà chúng tôi sẽ phải sử dụng nếu không. Trong quá trình ban đầu, dữ liệu phân đoạn chỉ tồn tại trong bảng phân đoạn trong một phần giây, do đó, nó không có giá trị gì về mặt bảo trì / bảo trì.
Cũng xin lưu ý rằng chúng tôi không thay thế mọi BULK INSERT
thao tác bằng TVP. Một số thao tác xử lý lượng dữ liệu lớn hơn và / hoặc không cần thực hiện bất kỳ điều gì đặc biệt với dữ liệu ngoài việc ném nó vào DB vẫn được sử dụng SqlBulkCopy
. Tôi không gợi ý rằng TVP là một liều thuốc chữa bách bệnh về hiệu suất, chỉ là chúng đã thành công SqlBulkCopy
trong trường hợp cụ thể này liên quan đến một số chuyển đổi giữa giai đoạn ban đầu và hợp nhất cuối cùng.
Vì vậy, bạn có nó. Point chuyển đến TToni để tìm liên kết phù hợp nhất, nhưng tôi cũng đánh giá cao các phản hồi khác. Cảm ơn một lần nữa!