Khi nào các cột được tính toán?


29

Khi nào các giá trị cho các cột được tính được xác định?

  • Khi giá trị được lấy?
  • Khi giá trị được thay đổi?
  • Một thời gian khác?

Tôi đoán đây là một câu hỏi mới vì tôi không tìm thấy gì trong các tìm kiếm của mình.

Câu trả lời:


19

Nó phụ thuộc vào cách bạn xác định cột được tính toán. Một PERSISTEDcộ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:

SQL SERVER - Cột được tính toán - PERSISTED và lưu trữ


6
Điều gì về nếu chúng được duy trì nhưng kế hoạch truy vấn sử dụng một chỉ mục không bao gồm cột đó? Tôi không chắc liệu bạn sẽ có được một tra cứu hay nếu nó chỉ tính toán nó một cách nhanh chóng và hiện không thể kiểm tra nó.
Martin Smith

1
@Martin bạn nói đúng, trong thử nghiệm của tôi, SQL Server đã chọn tính toán lại qua tra cứu.
Aaron Bertrand

34

Đ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:

nhập mô tả hình ảnh ở đây

nhập mô tả hình ảnh ở đây

Trong khi phiên bản bền bỉ chỉ hiển thị tính toán xảy ra trên insert:

nhập mô tả hình ảnh ở đây

nhập mô tả hình ảnh ở đây

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:

nhập mô tả hình ảnh ở đây

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 đánh giá cao, tôi không bao giờ đặt câu hỏi về hành vi của động cơ trong kết quả tính toán.
Arthur D

8
@ArthurD Đó là một quyết định tối ưu hóa dựa trên (hầu hết) dựa trên chi phí ước tính của từng phương án, xem câu trả lời của tôi cho một câu hỏi khác ở đây.
Paul White nói GoFundMonica

-1

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 persistedtừ 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ố.

tạo bảng với cột bền kế hoạch thực hiện chức năng hiển thị đang được thực hiện

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.