Câu trả lời:
Nó phụ thuộc vào cách bạn xác định cột được tính toán. Một PERSISTED
cột được tính toán sẽ được tính toán và sau đó được lưu trữ dưới dạng dữ liệu bên trong bảng. Nếu bạn không xác định cột là PERSISTED
, nó sẽ được tính khi truy vấn của bạn được chạy.
Xin vui lòng xem câu trả lời của Aaron cho một lời giải thích và bằng chứng tuyệt vời.
Pinal Dave cũng mô tả chi tiết điều này và cho thấy bằng chứng lưu trữ trong loạt bài của mình:
Điều này là rất dễ dàng để chứng minh trên của riêng bạn. Chúng ta có thể tạo một bảng với một cột được tính toán sử dụng hàm do người dùng xác định vô hướng, sau đó kiểm tra các gói và thống kê chức năng trước và sau khi cập nhật và chọn, và xem khi nào thực hiện được ghi lại.
Hãy nói rằng chúng ta có chức năng này:
CREATE FUNCTION dbo.mask(@x varchar(32))
RETURNS varchar(32) WITH SCHEMABINDING
AS
BEGIN
RETURN (SELECT 'XX' + SUBSTRING(@x, 3, LEN(@x)-4) + 'XXXX');
END
GO
Và bảng này:
CREATE TABLE dbo.Floobs
(
FloobID int IDENTITY(1,1),
Name varchar(32),
MaskedName AS CONVERT(varchar(32), dbo.mask(Name)),
CONSTRAINT pk_Floobs PRIMARY KEY(FloobID),
CONSTRAINT ck_Name CHECK (LEN(Name)>=8)
);
GO
Hãy kiểm tra sys.dm_exec_function_stats
(mới trong SQL Server 2016 và Azure SQL Database) trước và sau khi chèn, sau đó chọn:
SELECT o.name, s.execution_count
FROM sys.dm_exec_function_stats AS s
INNER JOIN sys.objects AS o
ON o.[object_id] = s.[object_id]
WHERE s.database_id = DB_ID();
INSERT dbo.Floobs(Name) VALUES('FrankieC');
SELECT o.name, s.execution_count
FROM sys.dm_exec_function_stats AS s
INNER JOIN sys.objects AS o
ON o.[object_id] = s.[object_id]
WHERE s.database_id = DB_ID();
SELECT * FROM dbo.Floobs;
SELECT o.name, s.execution_count
FROM sys.dm_exec_function_stats AS s
INNER JOIN sys.objects AS o
ON o.[object_id] = s.[object_id]
WHERE s.database_id = DB_ID();
Tôi thấy không có chức năng gọi trên chèn, chỉ trên chọn.
Bây giờ, thả các bảng và làm lại, lần này thay đổi cột thành PERSISTED
:
DROP TABLE dbo.Floobs;
GO
DROP FUNCTION dbo.mask;
GO
...
MaskedName AS CONVERT(varchar(32), dbo.mask(Name)) PERSISTED,
...
Và tôi thấy điều ngược lại xảy ra: Tôi nhận được một thực thi được ghi vào phần chèn, nhưng không phải trên phần chọn.
Bạn chưa có phiên bản SQL Server đủ hiện đại để sử dụng sys.dm_exec_function_stats
? Đừng lo lắng, điều này cũng được ghi lại trong các kế hoạch thực hiện .
Đối với phiên bản không tồn tại, chúng ta có thể thấy chức năng chỉ được tham chiếu trong phần chọn:
Trong khi phiên bản bền bỉ chỉ hiển thị tính toán xảy ra trên insert:
Bây giờ, Martin đưa ra một điểm tuyệt vời trong một nhận xét : điều này không phải lúc nào cũng đúng. Hãy tạo một chỉ mục không bao gồm cột được tính toán bền vững và chạy truy vấn sử dụng chỉ mục đó và xem liệu tra cứu có nhận được dữ liệu từ dữ liệu vẫn tồn tại hay tính toán dữ liệu khi chạy (chức năng thả và tạo lại và bảng ở đây):
CREATE INDEX x ON dbo.Floobs(Name);
GO
INSERT dbo.Floobs(name)
SELECT LEFT(name, 32)
FROM sys.all_columns
WHERE LEN(name) >= 8;
Bây giờ, chúng tôi sẽ chạy một truy vấn sử dụng chỉ mục (thực tế nó sử dụng chỉ mục theo mặc định trong trường hợp cụ thể này, ngay cả khi không có mệnh đề where):
SELECT * FROM dbo.Floobs WITH (INDEX(x))
WHERE Name LIKE 'S%';
Tôi thấy các thực thi bổ sung trong các số liệu thống kê chức năng và kế hoạch không nói dối:
Vì vậy, câu trả lời là TIỀN GỬI CNTT . Trong trường hợp này, SQL Server nghĩ rằng việc tính toán lại các giá trị sẽ rẻ hơn so với thực hiện tra cứu. Điều này có thể thay đổi do nhiều yếu tố khác nhau, vì vậy đừng dựa vào nó. Và điều này có thể xảy ra theo một trong hai hướng cho dù chức năng do người dùng xác định có được sử dụng hay không; Tôi chỉ sử dụng nó ở đây vì nó làm cho nó dễ dàng hơn để minh họa.
Câu trả lời cho câu hỏi này thực sự là "nó phụ thuộc." Tôi vừa chạy qua một ví dụ trong đó SQL Server đang sử dụng chỉ mục trên cột được tính toán bền vững nhưng nó vẫn đang thực hiện chức năng, như thể các giá trị không bao giờ được duy trì để bắt đầu. Nó có thể phải làm với kiểu dữ liệu của cột ( nvarchar(37)
) hoặc có thể là kích thước của bảng (khoảng 7 triệu hàng), nhưng SQL Server đã quyết định bỏ qua persisted
từ khóa, trong trường hợp cụ thể này.
Trong trường hợp này, khóa chính trên bảng là TransactionID cũng là một cột được tính toán và duy trì. Kế hoạch thực hiện đang tạo một quét chỉ mục và trong một bảng chỉ có 7 triệu hàng, truy vấn đơn giản này mất tới 2-3 phút để chạy vì chức năng được chạy lại trên mỗi hàng và các giá trị dường như không được duy trì chỉ số.