Suy nghĩ đầu tiên của tôi ở đây là - vấn đề hiệu suất là gì? Chắc chắn rằng bạn có một vòng lặp (một lần mỗi hàng để áp dụng ở đâu) trong một vòng lặp mà nó chạy một truy vấn. Nhưng bạn có đang nhận được kế hoạch thực hiện kém? Bộ kết quả của bạn có lớn không? Nhưng chúng ta hãy chuyển sang cái chung. Làm thế nào để một khi giải quyết vấn đề này? SQL không thực sự thực hiện ghi nhớ (như @Martin_Smith nổi tiếng đã chỉ ra). Vậy con trai phải làm sao?
Tùy chọn 1 - Thiết kế mới
Tạo một thiết kế hoàn toàn mới. Trong trường hợp cụ thể này, @Aaron_Bertrand chỉ ra rằng bảng lịch có thể đáp ứng nhu cầu của bạn. Khá đúng. Điều này không thực sự giúp bạn trong các tình huống không phải lịch, nhưng như thường lệ trong SQL, bạn cần suy nghĩ khác đi một chút.
Tùy chọn 2 - Gọi UDF ít hơn
Thu hẹp tập hợp các mục gọi chức năng này. Điều này nhắc tôi rất nhiều về cách thực hiện thành công đếm phân trang / hàng . Tạo một tập hợp kết quả nhỏ có các giá trị riêng biệt được yêu cầu và sau đó gọi UDF của bạn để nó chỉ được gọi một vài lần. Đây có thể là một tùy chọn hoặc không, nhưng có thể hoạt động trong nhiều trường hợp.
Tùy chọn 3 - UDF động
Có lẽ tôi sẽ bị la ó vì gợi ý này, nhưng rồi đây. Điều làm cho UDF này chậm là câu lệnh select bên trong vòng lặp. Nếu bảng Ngày lễ của bạn thực sự thay đổi không thường xuyên, bạn có thể đặt một kích hoạt trên bảng. Trình kích hoạt sẽ viết ra và cập nhật UDF. UDF mới có thể bạo hành tất cả các quyết định về kỳ nghỉ. Nó có hơi giống như ăn thịt đồng loại với SQL viết SQL không? Chắc chắn rồi. Nhưng nó sẽ loại bỏ truy vấn phụ và tăng tốc độ UDF. Hãy bắt đầu.
Tùy chọn 4 - Ghi nhớ!
Trong khi SQL không thể trực tiếp ghi nhớ, chúng tôi có SQL CLR. Chuyển đổi UDF sang udf SQL CLR. Trong CLR, bạn có thể sử dụng các biến tĩnh. Bạn có thể dễ dàng lấy bảng Ngày lễ vào một khoảng thời gian thường xuyên và lưu trữ chúng trong bảng băm. Sau đó, chỉ cần viết lại vòng lặp của bạn trong CLR. Bạn thậm chí có thể đi xa hơn và ghi nhớ toàn bộ câu trả lời nếu đó là logic phù hợp.
Cập nhật:
Tùy chọn 1 - Tôi thực sự đang cố gắng tập trung vào cái chung ở đây, không phải hàm ví dụ mà bạn đã sử dụng ở trên. Tuy nhiên, thiết kế hiện tại của UDF của bạn cho phép nhiều lệnh gọi đến bảng Ngày lễ nếu bạn tình cờ gặp một vài lệnh liên tiếp. Sử dụng một số loại bảng kiểu lịch có chứa danh sách 'những ngày tồi tệ' và 'ngày làm việc tiếp theo' tương ứng sẽ cho phép bạn loại bỏ khả năng có nhiều lần truy cập &truy vấn.
Tùy chọn 3 - Mặc dù miền không xác định trước thời hạn, bạn rất có thể sửa đổi bảng kỳ nghỉ của mình. Đối với một ngày lễ nhất định, nó sẽ chứa ngày làm việc tương ứng tiếp theo. Từ dữ liệu này, bạn có thể rút ra một UDF với một câu lệnh dài (khi '5/5/2012' rồi '5/14/2012' hoặc một cái gì đó tương tự) ở dưới cùng. Chiến lược này có thể không hoạt động với mọi loại vấn đề, nhưng có thể hoạt động tốt đối với một số loại vấn đề.
Lựa chọn 4 - Có những tác động đối với mọi công nghệ. CLR cần được triển khai, cấu hình SQL Server được sửa đổi và SQL CLR được giới hạn trong khuôn khổ 3.5. Cá nhân tôi thấy những điều chỉnh này đủ dễ dàng, nhưng tình huống của bạn có thể khác (giả sử DBA ngoan cố hoặc các hạn chế về sửa đổi đối với máy chủ sản xuất).
Việc sử dụng biến tĩnh yêu cầu tập hợp được được cấp FULL TRUST . Bạn sẽ phải đảm bảo rằng bạn đã khóa chính xác.
Có một số bằng chứng ở mức rất cao mức giao dịch CLR không hoạt động tốt như SQL trực tiếp. Tuy nhiên, trong trường hợp của bạn, quan sát này có thể không áp dụng được vì không có bản sửa lỗi SQL trực tiếp cho những gì bạn đang cố gắng thực hiện (memoize).