Đưa ra mã trong câu trả lời của bạn, rất có thể bạn sẽ cải thiện hiệu suất bằng cách thực hiện hai thay đổi sau:
Thực hiện hai điều đó sẽ làm giảm số lượng lớn các hoạt động ghi nhật ký tran và khóa / mở khóa mà bạn hiện đang tạo bằng cách thực hiện các câu lệnh DML riêng lẻ.
Thí dụ:
conn.Open();
using (SqlCommand cmd = new SqlCommand(
@"BEGIN TRAN;
UPDATE [TestTable] SET Column5 = 'some unique value' WHERE ID = 1;
UPDATE [TestTable] SET Column5 = 'some unique value' WHERE ID = 2;
...
UPDATE [TestTable] SET Column5 = 'some unique value' WHERE ID = 4500;
COMMIT TRAN;
", conn));
CẬP NHẬT
Câu hỏi hơi thưa thớt về các chi tiết. Mã ví dụ chỉ được hiển thị trong một câu trả lời .
Một lĩnh vực gây nhầm lẫn là mô tả đề cập đến việc cập nhật hai cột, tuy nhiên mã ví dụ chỉ hiển thị một cột duy nhất đang được cập nhật. Câu trả lời của tôi ở trên được dựa trên mã, do đó nó chỉ hiển thị một cột duy nhất. Nếu thực sự có hai cột để cập nhật, thì cả hai cột phải được cập nhật trong cùng một UPDATE
câu lệnh:
conn.Open();
using (SqlCommand cmd = new SqlCommand(
@"BEGIN TRAN;
UPDATE [TestTable]
SET Column5 = 'some unique value',
ColumnN = 'some unique value'
WHERE ID = 1;
UPDATE [TestTable]
SET Column5 = 'some unique value',
SET ColumnN = 'some unique value'
WHERE ID = 2;
...
UPDATE [TestTable]
SET Column5 = 'some unique value',
SET ColumnN = 'some unique value'
WHERE ID = 4500;
COMMIT TRAN;
", conn));
Một vấn đề khác không rõ ràng là dữ liệu "duy nhất" đến từ đâu? Câu hỏi đề cập rằng các giá trị duy nhất là GUID. Là những thứ này được tạo ra trong lớp ứng dụng? Có phải chúng đến từ một nguồn dữ liệu khác mà lớp ứng dụng biết và cơ sở dữ liệu không? Điều này rất quan trọng bởi vì, tùy thuộc vào câu trả lời cho những câu hỏi này, có thể có ý nghĩa khi hỏi:
- Thay vào đó, GUID có thể được tạo trong SQL Server không?
- Nếu có với # 1, thì có lý do nào để tạo mã này từ mã ứng dụng thay vì thực hiện một vòng lặp đơn giản trong T-SQL không?
Nếu "có" thành # 1 nhưng vì lý do nào đó, cần phải được tạo trong .NET, thì bạn có thể sử dụng NEWID()
và tạo các UPDATE
câu lệnh hoạt động trên phạm vi của các hàng, trong trường hợp đó bạn không cần BEGIN TRAN
/ 'CAM KẾT mỗi câu lệnh có thể xử lý tất cả 4500 hàng trong một lần chụp:
conn.Open();
using (SqlCommand cmd = new SqlCommand(
@"UPDATE [TestTable]
SET Column5 = NEWID(),
ColumnN = NEWID()
WHERE ID BETWEEN 1 and 4500;
", conn));
Nếu "có" với # 1 và không có lý do thực sự nào để các CẬP NHẬT này được tạo trong .NET, thì bạn có thể thực hiện các thao tác sau:
DECLARE @BatchSize INT = 4500, -- this could be an input param for a stored procedure
@RowsAffected INT = 1, -- needed to enter loop
@StartingID INT = 1; -- initial value
WHILE (@RowsAffected > 0)
BEGIN
UPDATE TOP (@BatchSize) tbl
SET tbl.Column5 = NEWID(),
tbl.ColumnN = NEWID()
FROM [TestTable] tbl
WHERE tbl.ID BETWEEN @StartingID AND (@StartingID + @BatchSize - 1);
SET @RowsAffected = @@ROWCOUNT;
SET @StartingID += @BatchSize;
END;
Mã ở trên chỉ hoạt động nếu các ID
giá trị không thưa thớt hoặc ít nhất là nếu các giá trị không có khoảng trống lớn hơn @BatchSize
, sao cho có ít nhất 1 hàng được cập nhật trong mỗi lần lặp. Mã này cũng giả định rằng ID
trường là Chỉ mục cụm. Các giả định này có vẻ hợp lý với mã ví dụ được cung cấp.
Tuy nhiên, nếu các ID
giá trị có khoảng trống lớn hoặc nếu ID
trường không phải là Chỉ mục cụm, thì bạn chỉ có thể kiểm tra các hàng chưa có giá trị:
DECLARE @BatchSize INT = 4500, -- this could be an input param for a stored procedure
@RowsAffected INT = 1; -- needed to enter loop
WHILE (@RowsAffected > 0)
BEGIN
UPDATE TOP (@BatchSize) tbl
SET tbl.Column5 = NEWID(),
tbl.ColumnN = NEWID()
FROM [TestTable] tbl
WHERE tbl.Col1 IS NULL;
SET @RowsAffected = @@ROWCOUNT;
END;
NHƯNG , nếu "không" đến # 1 và các giá trị đến từ .NET vì một lý do chính đáng, chẳng hạn như các giá trị duy nhất cho mỗi giá trị ID
đã tồn tại trong một nguồn khác, thì bạn vẫn có thể tăng tốc độ này (ngoài đề xuất ban đầu của tôi) bằng cách cung cấp một bảng dẫn xuất:
conn.Open();
using (SqlCommand cmd = new SqlCommand(
@"BEGIN TRAN;
UPDATE tbl
SET tbl.Column5 = tmp.Col1,
tbl.ColumnN = tmp.Col2
FROM [TestTable] tbl
INNER JOIN (VALUES
(1, 'some unique value A', 'some unique value B'),
(2, 'some unique value C', 'some unique value D'),
...
(1000, 'some unique value N1', 'some unique value N2')
) tmp (ID, Col1, Col2)
ON tmp.ID = tbl.ID;
UPDATE tbl
SET tbl.Column5 = tmp.Col1,
tbl.ColumnN = tmp.Col2
FROM [TestTable] tbl
INNER JOIN (VALUES
(1001, 'some unique value A2', 'some unique value B2'),
(1002, 'some unique value C2', 'some unique value D2'),
...
(2000, 'some unique value N3', 'some unique value N4')
) tmp (ID, Col1, Col2)
ON tmp.ID = tbl.ID;
COMMIT TRAN;
", conn));
Tôi tin rằng giới hạn về số lượng hàng có thể được tham gia VALUES
là 1000, vì vậy tôi đã nhóm hai bộ lại với nhau trong một giao dịch rõ ràng. Bạn có thể kiểm tra với tối đa 4 bộ trong số này UPDATE
để thực hiện 4000 mỗi giao dịch và giữ dưới giới hạn 5000 khóa.