답변:
계산 열을 정의하는 방법에 따라 다릅니다. PERSISTED
계산 열을 산출하고 내부 데이터 테이블로서 저장한다. 열을로 정의하지 않으면 PERSISTED
쿼리가 실행될 때 계산됩니다.
훌륭한 설명과 증거는 Aaron의 답변 을 참조하십시오 .
Pinal Dave 는 또한 이것을 자세히 설명하고 그의 시리즈에서 저장 증명을 보여줍니다.
이것은 스스로 증명하기가 매우 쉽습니다. 스칼라 사용자 정의 함수를 사용하는 계산 열이있는 테이블을 만든 다음 업데이트 및 선택 전후에 계획 및 함수 통계를 확인하고 실행 기록시기를 확인할 수 있습니다.
이 기능이 있다고 가정 해 봅시다.
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
그리고이 테이블 :
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
sys.dm_exec_function_stats
삽입 전후에 그리고 선택 후에 확인합니다 (SQL Server 2016 및 Azure SQL 데이터베이스의 새로운 기능).
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();
삽입물에 대한 함수 호출이 없으며 선택 항목에만 표시됩니다.
이제 테이블을 삭제하고 다시 수행하십시오. 이번에는 열을 PERSISTED
다음 으로 변경하십시오 .
DROP TABLE dbo.Floobs;
GO
DROP FUNCTION dbo.mask;
GO
...
MaskedName AS CONVERT(varchar(32), dbo.mask(Name)) PERSISTED,
...
그리고 나는 반대의 일이 발생하는 것을 본다.
사용할 수있는 최신 버전의 SQL Server가 sys.dm_exec_function_stats
없습니까? 걱정하지 마십시오. 이것은 실행 계획에서도 캡처됩니다 .
비 지속 버전의 경우 select에서만 함수가 참조되는 것을 볼 수 있습니다.
지속 버전은 삽입시 발생하는 계산 만 보여줍니다.
이제 Martin은 의견에서 큰 지적을 합니다. 항상 그런 것은 아닙니다. 지속 형 계산 열을 다루지 않는 인덱스를 생성하고 해당 인덱스를 사용하는 쿼리를 실행하고 조회가 기존의 지속 형 데이터에서 데이터를 가져 오거나 런타임에 데이터를 계산하는지 확인 (삭제 및 재 작성 기능) 그리고 여기에 테이블) :
CREATE INDEX x ON dbo.Floobs(Name);
GO
INSERT dbo.Floobs(name)
SELECT LEFT(name, 32)
FROM sys.all_columns
WHERE LEN(name) >= 8;
이제 인덱스를 사용하는 쿼리를 실행합니다 (실제로 where 절 없이도이 특정 경우에는 기본적으로 인덱스를 사용합니다).
SELECT * FROM dbo.Floobs WITH (INDEX(x))
WHERE Name LIKE 'S%';
함수 통계에 추가 실행이 표시되고 계획이 거짓말하지 않습니다.
답은 IT DEPENDS 입니다. 이 경우 SQL Server는 조회를 수행하는 것보다 값을 다시 계산하는 것이 더 저렴하다고 생각했습니다. 이것은 다양한 요인으로 인해 변경 될 수 있으므로 의존하지 마십시오. 그리고 이것은 사용자 정의 함수의 사용 여부에 관계없이 어느 방향 으로든 발생할 수 있습니다. 설명하기가 훨씬 쉽기 때문에 여기서 만 사용했습니다.
이 질문에 대한 답은 실제로 "의존"입니다. SQL Server가 지속 계산 열에서 인덱스를 사용하는 예제를 방금 실행했지만 값이 시작되지 않는 것처럼 여전히 함수를 수행하고 있습니다. 열의 데이터 형식 ( nvarchar(37)
) 또는 테이블 크기 (약 700 만 행)와 관련이있을 수 있지만 SQL Server는 persisted
키워드 를 무시하기로 결정했습니다 .
이 경우 테이블의 기본 키는 TransactionID이며 계산 및 지속 열이기도합니다. 실행 계획은 인덱스 스캔을 생성하고 있으며 7 백만 행만있는 테이블에서이 간단한 쿼리는 함수가 모든 행에서 다시 실행되고 값이 지속되지 않는 것으로 나타나기 때문에 실행하는 데 2-3 분 이상이 걸립니다. 인덱스