Trong bài đăng cuối cùng của tôi, "Một cách để lấy chỉ mục tìm kiếm ký tự đại diện đứng đầu", tôi đã đề cập rằng bạn sẽ cần các trình kích hoạt để giải quyết việc duy trì các phân đoạn mà tôi đã đề xuất. Một vài người đã liên hệ với tôi để hỏi liệu tôi có thể chứng minh những yếu tố kích hoạt đó không.
Để đơn giản hóa từ bài viết trước, hãy giả sử chúng ta có các bảng sau - một tập hợp các Công ty và sau đó là bảng CompanyNameFragment cho phép tìm kiếm ký tự đại diện giả dựa trên bất kỳ chuỗi con nào của tên công ty:
CREATE TABLE dbo.Companies ( CompanyID int CONSTRAINT PK_Companies PRIMARY KEY, Name nvarchar(100) NOT NULL ); GO CREATE TABLE dbo.CompanyNameFragments ( CompanyID int NOT NULL, Fragment nvarchar(100) NOT NULL ); CREATE CLUSTERED INDEX CIX_CNF ON dbo.CompanyNameFragments(Fragment, CompanyID);
Cung cấp chức năng này để tạo các đoạn (thay đổi duy nhất so với bài viết gốc là tôi đã tăng @input
hỗ trợ 100 ký tự):
CREATE FUNCTION dbo.CreateStringFragments( @input nvarchar(100) ) RETURNS TABLE WITH SCHEMABINDING AS RETURN ( WITH x(x) AS ( SELECT 1 UNION ALL SELECT x+1 FROM x WHERE x < (LEN(@input)) ) SELECT Fragment = SUBSTRING(@input, x, LEN(@input)) FROM x ); GO
Chúng tôi có thể tạo một trình kích hoạt duy nhất có thể xử lý cả ba hoạt động:
CREATE TRIGGER dbo.Company_MaintainFragments ON dbo.Companies FOR INSERT, UPDATE, DELETE AS BEGIN SET NOCOUNT ON; DELETE f FROM dbo.CompanyNameFragments AS f INNER JOIN deleted AS d ON f.CompanyID = d.CompanyID; INSERT dbo.CompanyNameFragments(CompanyID, Fragment) SELECT i.CompanyID, fn.Fragment FROM inserted AS i CROSS APPLY dbo.CreateStringFragments(i.Name) AS fn; END GO
Điều này hoạt động mà không cần kiểm tra xem loại hoạt động nào đã xảy ra vì:
- Đối với CẬP NHẬT hoặc XÓA, XÓA sẽ xảy ra - đối với CẬP NHẬT, chúng tôi sẽ không bận tâm đến việc khớp các đoạn mà vẫn giữ nguyên; chúng tôi sẽ thổi bay tất cả chúng đi, vì vậy chúng có thể được thay thế hàng loạt. Đối với INSERT, câu lệnh DELETE sẽ không có hiệu lực, vì sẽ không có hàng nào trong
deleted
. - Đối với INSERT hoặc UPDATE, INSERT sẽ xảy ra. Đối với một DELETE, câu lệnh INSERT sẽ không có hiệu lực, vì sẽ không có hàng nào trong
inserted
.
Bây giờ, chỉ để đảm bảo nó hoạt động, hãy thực hiện một số thay đổi đối với Companies
bảng và sau đó kiểm tra hai bảng của chúng tôi.
-- First, let's insert two companies -- (table contents after insert shown in figure 1 below) INSERT dbo.Companies(Name) VALUES(N'Banana'), (N'Acme Corp'); -- Now, let's update company 2 to 'Orange' -- (table contents after update shown in figure 2 below): UPDATE dbo.Companies SET Name = N'Orange' WHERE CompanyID = 2; -- Finally, delete company #1 -- (table contents after delete shown in figure 3 below): DELETE dbo.Companies WHERE CompanyID = 1;
Hình 1: Nội dung bảng ban đầu | Hình 2: Nội dung bảng sau khi cập nhật | Hình 3: Nội dung bảng sau khi xóa |
Lưu ý (dành cho những người toàn vẹn tham chiếu)
Lưu ý rằng nếu bạn thiết lập khóa ngoại thích hợp giữa hai bảng này, bạn sẽ phải sử dụng trình kích hoạt thay vì trình kích hoạt để xử lý việc xóa, nếu không bạn sẽ gặp vấn đề về gà và trứng - bạn không thể đợi cho đến khi * sau khi * cha mẹ hàng bị xóa để loại bỏ các hàng con. Vì vậy, bạn sẽ phải thiết lập ON DELETE CASCADE
(mà cá nhân tôi không có xu hướng thích), hoặc hai trình kích hoạt của bạn sẽ trông giống như thế này (trình kích hoạt sau vẫn phải thực hiện cặp DELETE / INSERT trong trường hợp CẬP NHẬT):
CREATE TRIGGER dbo.Company_DeleteFragments ON dbo.Companies INSTEAD OF DELETE AS BEGIN SET NOCOUNT ON; DELETE f FROM dbo.CompanyNameFragments AS f INNER JOIN deleted AS d ON f.CompanyID = d.CompanyID; DELETE c FROM dbo.Companies AS c INNER JOIN deleted AS d ON c.CompanyID = d.CompanyID; END GO CREATE TRIGGER dbo.Company_MaintainFragments ON dbo.Companies FOR INSERT, UPDATE AS BEGIN SET NOCOUNT ON; DELETE f FROM dbo.CompanyNameFragments AS f INNER JOIN deleted AS d ON f.CompanyID = d.CompanyID; INSERT dbo.CompanyNameFragments(CompanyID, Fragment) SELECT i.CompanyID, fn.Fragment FROM inserted AS i CROSS APPLY dbo.CreateStringFragments(i.Name) AS fn; END GO
Tóm tắt
Bài đăng này nhằm mục đích cho thấy việc thiết lập trình kích hoạt sẽ dễ dàng như thế nào sẽ duy trì tính năng có thể tìm kiếm các đoạn chuỗi để cải thiện các tìm kiếm theo ký tự đại diện, ít nhất là đối với các chuỗi có kích thước vừa phải. Bây giờ, tôi vẫn biết rằng loại này xuất hiện như một ý tưởng kỳ quặc, nhưng tôi vẫn tiếp tục nói về nó bởi vì tôi tin rằng có những trường hợp sử dụng tốt ngoài kia.
Trong bài đăng tiếp theo của tôi, tôi sẽ chỉ ra cách xem tác động của lựa chọn này:Bạn có thể dễ dàng thiết lập khối lượng công việc đại diện để so sánh chi phí tài nguyên của việc duy trì các phân đoạn với hiệu suất tiết kiệm tại thời điểm truy vấn. Tôi sẽ xem xét các độ dài chuỗi khác nhau cũng như các cân bằng khối lượng công việc khác nhau (chủ yếu là đọc so với chủ yếu là viết) và cố gắng tìm ra các điểm ngọt ngào và khu vực nguy hiểm.