Sqlserver
 sql >> Cơ Sở Dữ Liệu >  >> RDS >> Sqlserver

Sự cố với hiệu suất tham số giá trị bảng

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.

  1. 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:
  2. 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);
    
  3. 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ớ

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ện INSERT 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:
    1. 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à
    2. xây dựng VALUES (), (), ... , ngay cả khi thực hiện INSERT 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.

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



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Tính toàn vẹn của giao dịch của tôi bị mất với ngoại lệ TransactionInDoubtException

  2. Toán tử OR Ngắn mạch trong SQL Server

  3. Gọi thủ tục được lưu trữ với giá trị trả về

  4. Làm thế nào để so sánh các phiên bản phần mềm sử dụng SQL Server?

  5. Khi nào thì tốt hơn nên viết sql ad hoc so với các thủ tục được lưu trữ