Đúng.
Không chỉ định WITH SCHEMABINDING
có nghĩa là SQL Server bỏ qua các kiểm tra chi tiết mà nó thường thực hiện trên thân hàm. Nó chỉ đơn giản đánh dấu chức năng là truy cập dữ liệu (như được đề cập trong liên kết được đưa ra trong câu hỏi).
Đây là một tối ưu hóa hiệu suất. Nếu nó không đưa ra giả định này, SQL Server sẽ phải thực hiện kiểm tra chi tiết cho mọi lời gọi hàm (vì hàm không liên kết có thể thay đổi bất cứ lúc nào).
Có năm thuộc tính chức năng quan trọng:
- Chủ nghĩa quyết đoán
- Độ chính xác
- Truy cập dữ liệu
- Truy cập dữ liệu hệ thống
- Xác minh hệ thống
Ví dụ: lấy hàm vô hướng sau:
CREATE FUNCTION dbo.F
(
@i integer
)
RETURNS datetime
AS
BEGIN
RETURN '19000101';
END;
Chúng ta có thể xem xét năm thuộc tính bằng hàm siêu dữ liệu:
SELECT
IsDeterministic = OBJECTPROPERTYEX(Func.ID, 'IsDeterministic'),
IsPrecise = OBJECTPROPERTYEX(Func.ID, 'IsPrecise'),
IsSystemVerified = OBJECTPROPERTYEX(Func.ID, 'IsSystemVerified'),
UserDataAccess = OBJECTPROPERTYEX(Func.ID, 'UserDataAccess'),
SystemDataAccess = OBJECTPROPERTYEX(Func.ID, 'SystemDataAccess')
FROM (VALUES(OBJECT_ID(N'dbo.F', N'FN'))) AS Func (ID);
Hai thuộc tính truy cập dữ liệu đã được đặt thành đúng và ba thuộc tính khác được đặt thành sai .
Điều này có ý nghĩa vượt ra ngoài những điều có thể được mong đợi (ví dụ, sử dụng trong các chế độ xem được lập chỉ mục hoặc các cột được tính toán được lập chỉ mục).
Hiệu ứng trên trình tối ưu hóa truy vấn
Các định mệnh bất động sản nói riêng ảnh hưởng đến truy vấn tối ưu. Nó có các quy tắc chi tiết liên quan đến các loại viết lại và thao tác mà nó được phép thực hiện, và những điều này bị hạn chế rất nhiều cho các yếu tố không xác định. Các tác dụng phụ có thể khá tinh tế.
Ví dụ, hãy xem xét hai bảng sau:
CREATE TABLE dbo.T1
(
SomeInteger integer PRIMARY KEY
);
GO
CREATE TABLE dbo.T2
(
SomeDate datetime PRIMARY KEY
);
... và một truy vấn sử dụng hàm (như được xác định trước đó):
SELECT *
FROM dbo.T1 AS T1
JOIN dbo.T2 AS T2
ON T2.SomeDate = dbo.F(T1.SomeInteger);
Kế hoạch truy vấn như mong đợi, bao gồm tìm kiếm vào bảng T2:
Tuy nhiên, nếu cùng một truy vấn logic được viết bằng bảng dẫn xuất hoặc biểu thức bảng chung:
WITH CTE AS
(
SELECT *, dt = dbo.F(T1.SomeInteger)
FROM dbo.T1 AS T1
)
SELECT *
FROM CTE
JOIN dbo.T2 AS T2
ON T2.SomeDate = CTE.dt;
-- Derived table
SELECT
*
FROM
(
SELECT *, dt = dbo.F(T1.SomeInteger)
FROM dbo.T1 AS T1
) AS T1
JOIN dbo.T2 AS T2
ON T2.SomeDate = T1.dt;
Kế hoạch thực hiện hiện có tính năng quét, với vị từ liên quan đến chức năng bị mắc kẹt trong Bộ lọc:
Điều này cũng xảy ra nếu bảng dẫn xuất hoặc biểu thức bảng chung được thay thế bằng hàm xem hoặc hàm trong dòng. Một FORCESEEK
gợi ý (và các nỗ lực tương tự khác) sẽ không thành công:
Vấn đề cơ bản là trình tối ưu hóa truy vấn không thể sắp xếp lại các yếu tố truy vấn không xác định là tự do .
Để thực hiện tìm kiếm, vị từ Bộ lọc sẽ cần được chuyển xuống kế hoạch để truy cập dữ liệu T2. Chuyển động này được ngăn chặn khi chức năng không xác định.
Sửa chữa
Khắc phục cho ví dụ này bao gồm hai bước:
- Thêm vào
WITH SCHEMABINDING
- Làm cho hàm xác định
Bước đầu tiên là tầm thường. Thứ hai liên quan đến việc loại bỏ các hàm ẩn không xác định từ chuỗi sang datetime
; thay thế nó bằng một quyết định CONVERT
. Bản thân nó cũng không đủ .
ALTER FUNCTION dbo.F
(
@i integer
)
RETURNS datetime
WITH SCHEMABINDING
AS
BEGIN
-- Convert with a deterministic style
RETURN CONVERT(datetime, '19000101', 112);
END;
Các thuộc tính chức năng là:
Với trình tối ưu hóa được giải phóng, tất cả các ví dụ hiện tạo ra kế hoạch tìm kiếm mong muốn .
Lưu ý rằng việc sử dụng một CAST
để datetime
trong chức năng sẽ không hoạt động, bởi vì nó không thể xác định một phong cách chuyển đổi trong cú pháp rằng:
ALTER FUNCTION dbo.F
(
@i integer
)
RETURNS datetime
WITH SCHEMABINDING
AS
BEGIN
-- Convert with a deterministic style
RETURN CAST('19000101' AS datetime);
END;
Định nghĩa hàm này tạo ra kế hoạch quét và các thuộc tính cho thấy nó vẫn không xác định: