Dòng dưới cùng : Thêm tiêu chí vào WHERE
mệnh đề và chia truy vấn thành bốn truy vấn riêng biệt, một truy vấn cho mỗi trường cho phép máy chủ SQL cung cấp một kế hoạch song song và làm cho truy vấn chạy nhanh gấp 4 lần mà không cần kiểm tra thêm trong WHERE
mệnh đề. Chia các truy vấn thành bốn mà không có kiểm tra đã không làm điều đó. Không thêm kiểm tra mà không tách các truy vấn. Tối ưu hóa thử nghiệm giảm tổng thời gian chạy xuống còn 3 phút (từ 3 giờ ban đầu).
UDF ban đầu của tôi mất 3 giờ 16 phút để xử lý 1.174.731 hàng, với 1.216 GB dữ liệu nvarchar được thử nghiệm. Sử dụng CLR do Martin Smith cung cấp trong câu trả lời của mình, kế hoạch thực hiện vẫn không song song và nhiệm vụ mất 3 giờ 5 phút.
Đọc được WHERE
các tiêu chí đó có thể giúp đẩy UPDATE
song song, tôi đã làm như sau. Tôi đã thêm một chức năng vào mô-đun CLR để xem trường có khớp với biểu thức chính quy không:
[SqlFunction(IsDeterministic = true,
IsPrecise = true,
DataAccess = DataAccessKind.None,
SystemDataAccess = SystemDataAccessKind.None)]
public static SqlBoolean CanReplaceMultiWord(SqlString inputString, SqlXml replacementSpec)
{
string s = replacementSpec.Value;
ReplaceSpecification rs;
if (!cachedSpecs.TryGetValue(s, out rs))
{
var doc = new XmlDocument();
doc.LoadXml(s);
rs = new ReplaceSpecification(doc);
cachedSpecs[s] = rs;
}
return rs.IsMatch(inputString.ToString());
}
và, trong internal class ReplaceSpecification
, tôi đã thêm mã để thực hiện kiểm tra đối với biểu thức chính quy
internal bool IsMatch(string inputString)
{
if (Regex == null)
return false;
return Regex.IsMatch(inputString);
}
Nếu tất cả các trường được kiểm tra trong một câu lệnh, máy chủ SQL không song song hóa công việc
UPDATE dbo.DeidentifiedTest
SET IndexedXml = dbo.ReplaceMultiWord(IndexedXml, @X),
DE461 = dbo.ReplaceMultiWord(DE461, @X),
DE87 = dbo.ReplaceMultiWord(DE87, @X),
DE15 = dbo.ReplaceMultiWord(DE15, @X)
WHERE InProcess = 1
AND (dbo.CanReplaceMultiWord(IndexedXml, @X) = 1
OR DE15 = dbo.ReplaceMultiWord(DE15, @X)
OR dbo.CanReplaceMultiWord(DE87, @X) = 1
OR dbo.CanReplaceMultiWord(DE15, @X) = 1);
Thời gian thực hiện hơn 4 tiếng rưỡi và vẫn chạy. Kế hoạch thực hiện:
Tuy nhiên, nếu các trường được phân tách thành các câu lệnh riêng biệt, kế hoạch làm việc song song được sử dụng và mức sử dụng CPU của tôi tăng từ 12% với các kế hoạch nối tiếp đến 100% với các kế hoạch song song (8 lõi).
UPDATE dbo.DeidentifiedTest
SET IndexedXml = dbo.ReplaceMultiWord(IndexedXml, @X)
WHERE InProcess = 1
AND dbo.CanReplaceMultiWord(IndexedXml, @X) = 1;
UPDATE dbo.DeidentifiedTest
SET DE461 = dbo.ReplaceMultiWord(DE461, @X)
WHERE InProcess = 1
AND dbo.CanReplaceMultiWord(DE461, @X) = 1;
UPDATE dbo.DeidentifiedTest
SET DE87 = dbo.ReplaceMultiWord(DE87, @X)
WHERE InProcess = 1
AND dbo.CanReplaceMultiWord(DE87, @X) = 1;
UPDATE dbo.DeidentifiedTest
SET DE15 = dbo.ReplaceMultiWord(DE15, @X)
WHERE InProcess = 1
AND dbo.CanReplaceMultiWord(DE15, @X) = 1;
Thời gian thực hiện 46 phút. Thống kê hàng cho thấy khoảng 0,5% hồ sơ có ít nhất một trận đấu regex. Kế hoạch thực hiện:
Bây giờ, kéo chính về thời gian là WHERE
mệnh đề. Sau đó, tôi đã thay thế bài kiểm tra regex trong WHERE
mệnh đề bằng thuật toán Aho-Corasick được triển khai dưới dạng CLR. Điều này giảm tổng thời gian xuống còn 3 phút 6 giây.
Điều này đòi hỏi những thay đổi sau đây. Tải lắp ráp và các chức năng cho thuật toán Aho-Corasick. Thay đổi WHERE
mệnh đề thành
WHERE InProcess = 1 AND dbo.ContainsWordsByObject(ISNULL(FieldBeingTestedGoesHere,'x'), @ac) = 1;
Và thêm vào sau đây trước UPDATE
DECLARE @ac NVARCHAR(32);
SET @ac = dbo.CreateAhoCorasick(
(SELECT NAMES FROM dbo.NamesMultiWord FOR XML RAW, root('root')),
'en-us:i'
);
SELECT @var = REPLACE ... ORDER BY
xây dựng không được đảm bảo để làm việc như bạn mong đợi. Ví dụ Kết nối mục (xem phản hồi từ Microsoft). Vì vậy, chuyển sang SQLCLR có thêm lợi thế là đảm bảo kết quả chính xác, luôn luôn tốt.