Nếu TVP "chậm hơn đáng kể" so với các tùy chọn khác, thì rất có thể bạn đang triển khai chúng không chính xác.
- Bạn không nên sử dụng DataTable, trừ khi ứng dụng của bạn sử dụng nó ngoài việc gửi các giá trị đến TVP. Sử dụng
IEnumerable<SqlDataRecord>
giao diện nhanh hơn và sử dụng ít bộ nhớ hơn vì bạn không sao chép bộ sưu tập trong bộ nhớ chỉ để gửi nó đến DB. Tôi đã ghi lại điều này ở những nơi sau:- Làm cách nào để chèn 10 triệu bản ghi trong thời gian ngắn nhất có thể? (rất nhiều thông tin bổ sung và liên kết ở đây)
- Chuyển từ điển sang thủ tục lưu trữ T-SQL
- Dữ liệu truyền trực tuyến Vào SQL Server 2008 từ một ứng dụng (trên SQLServerCentral.com; yêu cầu đăng ký miễn phí)
-
Bạn không nên sử dụng
AddWithValue
cho SqlParameter, mặc dù đây không phải là vấn đề về hiệu suất. Nhưng vẫn phải:SqlParameter tvp = com.Parameters.Add("data", SqlDbType.Structured); tvp.Value = MethodThatReturnsIEnumerable<SqlDataRecord>(MyCollection);
- TVP là các Biến trong Bảng và như vậy không duy trì thống kê. Có nghĩa là, chúng chỉ báo cáo có 1 hàng cho Trình tối ưu hoá Truy vấn. Vì vậy, trong chương trình của bạn, hãy:
- Sử dụng biên dịch lại cấp câu lệnh cho bất kỳ truy vấn nào sử dụng TVP cho bất kỳ thứ gì khác ngoài lệnh SELECT:
OPTION (RECOMPILE)
đơn giản - Tạo một bảng tạm thời cục bộ (tức là một
#
) và sao chép nội dung của TVP vào bảng tạm thời - Bạn có thể thử thêm khóa chính được phân cụm vào Loại bảng do người dùng xác định
- Nếu sử dụng SQL Server 2014 hoặc mới hơn, bạn có thể thử sử dụng các bảng OLTP / bộ nhớ được tối ưu hóa trong bộ nhớ. Vui lòng xem: Bảng tạm thời nhanh hơn và biến bảng bằng cách sử dụng tối ưu hóa bộ nhớ
- Sử dụng biên dịch lại cấp câu lệnh cho bất kỳ truy vấn nào sử dụng TVP cho bất kỳ thứ gì khác ngoài lệnh SELECT:
Về lý do bạn nhìn thấy:
insert into @data ( ... fields ... ) values ( ... values ... )
-- for each row
insert into @data ( ... fields ... ) values ( ... values ... )
thay vì:
insert into @data ( ... fields ... )
values ( ... values ... ),
( ... values ... ),
NẾU đó thực sự là những gì đang xảy ra, thì:
- Nếu việc chèn được thực hiện trong một Giao dịch thì không có sự khác biệt về hiệu suất thực sự
- Cú pháp danh sách giá trị mới hơn (tức là
VALUES (row1), (row2), (row3)
) được giới hạn ở một số thứ như 1000 hàng và do đó không phải là một lựa chọn khả thi cho các TVP không có giới hạn đó. TUY NHIÊN, đây không phải là lý do mà các chèn riêng lẻ đang được sử dụng, vì không có giới hạn khi thực hiệnINSERT INTO @data (fields) SELECT tab.[col] FROM (VALUES (), (), ...) tab([col])
, mà tôi đã ghi lại ở đây: Số lượng hàng tối đa cho hàm tạo giá trị bảng . Thay vào đó ... - Lý do rất có thể là việc thực hiện các lần chèn riêng lẻ cho phép truyền trực tuyến các giá trị từ mã ứng dụng vào SQL Server:
- sử dụng trình lặp (tức là
IEnumerable<SqlDataRecord>
được lưu ý trong # 1 ở trên), mã ứng dụng gửi từng hàng khi nó được trả về từ phương thức và - xây dựng
VALUES (), (), ...
, ngay cả khi thực hiệnINSERT INTO ... SELECT FROM (VALUES ...)
phương pháp tiếp cận (không giới hạn ở 1000 hàng), vẫn yêu cầu xây dựng toàn bộVALUES
danh sách trước khi gửi bất kỳ dữ liệu vào SQL Server. Nếu có nhiều dữ liệu, sẽ mất nhiều thời gian hơn để tạo chuỗi siêu dài và sẽ chiếm nhiều bộ nhớ hơn khi thực hiện.
- sử dụng trình lặp (tức là
Vui lòng xem báo cáo chính thức này từ Nhóm tư vấn khách hàng của SQL Server: Tối đa hóa thông lượng với TVP