계산 열은 언제 계산됩니까?


29

계산 열의 값은 언제 결정됩니까?

  • 값을 검색 할 때
  • 값이 변경되면?
  • 다른 시간?

내 검색에서 아무것도 찾지 못했기 때문에 이것이 초보자 질문이라고 생각합니다.

답변:


19

계산 열을 정의하는 방법에 따라 다릅니다. PERSISTED계산 열을 산출하고 내부 데이터 테이블로서 저장한다. 열을로 정의하지 않으면 PERSISTED쿼리가 실행될 때 계산됩니다.

훌륭한 설명과 증거는 Aaron의 답변 을 참조하십시오 .

Pinal Dave 는 또한 이것을 자세히 설명하고 그의 시리즈에서 저장 증명을 보여줍니다.

SQL SERVER – 계산 열 – PERSISTED 및 스토리지


6
지속되지만 쿼리 계획에서 해당 열을 다루지 않는 인덱스를 사용하는 경우는 어떻습니까? 조회를 얻을지 또는 즉시 계산하여 현재 테스트 할 수 있는지 확실하지 않습니다.
Martin Smith

1
@Martin 당신 말이 맞아, 내 테스트에서 SQL Server는 조회를 통해 다시 계산을 선택했다.
Aaron Bertrand

34

이것은 스스로 증명하기가 매우 쉽습니다. 스칼라 사용자 정의 함수를 사용하는 계산 열이있는 테이블을 만든 다음 업데이트 및 선택 전후에 계획 및 함수 통계를 확인하고 실행 기록시기를 확인할 수 있습니다.

이 기능이 있다고 가정 해 봅시다.

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는 조회를 수행하는 것보다 값을 다시 계산하는 것이 더 저렴하다고 생각했습니다. 이것은 다양한 요인으로 인해 변경 될 수 있으므로 의존하지 마십시오. 그리고 이것은 사용자 정의 함수의 사용 여부에 관계없이 어느 방향 으로든 발생할 수 있습니다. 설명하기가 훨씬 쉽기 때문에 여기서 만 사용했습니다.


많은 계산, 나는 결과를 계산할 때 엔진의 행동에 의문을 제기하지 않았습니다.
Arthur D

8
@ArthurD 각 대안의 예상 비용을 바탕으로 한 최적화 결정 입니다. 여기에서 다른 질문에 대한 나의 대답 을보십시오.
Paul White에 따르면 GoFundMonica는

-1

이 질문에 대한 답은 실제로 "의존"입니다. SQL Server가 지속 계산 열에서 인덱스를 사용하는 예제를 방금 실행했지만 값이 시작되지 않는 것처럼 여전히 함수를 수행하고 있습니다. 열의 데이터 형식 ( nvarchar(37)) 또는 테이블 크기 (약 700 만 행)와 관련이있을 수 있지만 SQL Server는 persisted키워드 를 무시하기로 결정했습니다 .

이 경우 테이블의 기본 키는 TransactionID이며 계산 및 지속 열이기도합니다. 실행 계획은 인덱스 스캔을 생성하고 있으며 7 백만 행만있는 테이블에서이 간단한 쿼리는 함수가 모든 행에서 다시 실행되고 값이 지속되지 않는 것으로 나타나기 때문에 실행하는 데 2-3 분 이상이 걸립니다. 인덱스

지속 열이있는 테이블 작성 실행 계획을 보여주는 실행 계획

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.