계산 열에서 필터링 된 인덱스를 만들 수 없음


18

내 이전 질문 에서 테이블에 새 계산 열을 추가하는 동안 잠금 에스컬레이션을 비활성화하는 것이 좋은 생각입니까? 계산 열을 만들고 있습니다.

ALTER TABLE dbo.tblBGiftVoucherItem
ADD isUsGift AS CAST
(
    ISNULL(
        CASE WHEN sintMarketID = 2 
            AND strType = 'CARD'
            AND strTier1 LIKE 'GG%' 
        THEN 1 
        ELSE 0 
        END
    , 0) 
    AS BIT
) PERSISTED;

계산 된 열은 PERSISTED이며 computed_column_definition (Transact-SQL) 에 따라 다음과 같습니다.

갈망

데이터베이스 엔진이 계산 된 값을 테이블에 실제로 저장하고 계산 된 열이 종속 된 다른 열이 업데이트 될 때 값을 업데이트하도록 지정합니다. 계산 열을 PERSISTED로 표시하면 결정적이지만 정확하지 않은 계산 열에서 인덱스를 만들 수 있습니다. 자세한 내용은 계산 열 인덱스를 참조하십시오. 분할 된 테이블의 분할 열로 사용 된 계산 열은 명시 적으로 PERSISTED로 표시되어야합니다. PERSISTED가 지정되면 computed_column_expression이 결정적이어야합니다.

그러나 열에 색인을 만들려고하면 다음 오류가 발생합니다.

CREATE INDEX FIX_tblBGiftVoucherItem_incl
ON dbo.tblBGiftVoucherItem (strItemNo) 
INCLUDE (strTier3)
WHERE isUsGift = 1;

필터 표현식의 'isUsGift'열이 계산 열이므로 'dbo.tblBGiftVoucherItem'테이블에서 필터링 된 인덱스 'FIX_tblBGiftVoucherItem_incl'을 작성할 수 없습니다. 이 열을 포함하지 않도록 필터 표현식을 다시 작성하십시오.

계산 열에서 필터링 된 인덱스를 만들려면 어떻게합니까?

또는

대체 솔루션이 있습니까?


3
필터링 된 인덱스를 만들 수 있습니다 WHERE (sintMarketID = 2 AND strType = 'CARD' AND strTier1 LIKE 'GG%').
ypercubeᵀᴹ

답변:


21

불행히도 SQL Server 2014부터는 Filtered Index필터가 계산 열에 있는지 여부에 관계없이 필터가 있는 위치 를 만들 수 없습니다.

거기에있다 연결 항목 2009 열려있는, 그래서 그것을 위해 가서 투표하십시오. 어쩌면 Microsoft는이 날을 고칠 것입니다.

Aaron Bertrand는 Filtered Indexes 와 관련된 여러 가지 다른 문제를 다루는 기사를 가지고 있습니다.


21

지속 열에서 필터링 된 인덱스를 만들 수는 없지만 사용할 수있는 매우 간단한 해결 방법이 있습니다.

테스트로, IDENTITY열이 있는 간단한 테이블과 ID 열을 기반으로 지속 계산 열을 만들었습니다 .

USE tempdb;

CREATE TABLE dbo.PersistedViewTest
(
    PersistedViewTest_ID INT NOT NULL
        CONSTRAINT PK_PersistedViewTest
        PRIMARY KEY CLUSTERED
        IDENTITY(1,1)
    , SomeData VARCHAR(2000) NOT NULL
    , TestComputedColumn AS (PersistedViewTest_ID - 1) PERSISTED
);
GO

그런 다음 계산 열에 필터가있는 테이블을 기반으로 스키마 바운드 뷰를 만들었습니다.

CREATE VIEW dbo.PersistedViewTest_View
WITH SCHEMABINDING
AS
SELECT PersistedViewTest_ID
    , SomeData 
    , TestComputedColumn
FROM dbo.PersistedViewTest
WHERE TestComputedColumn < CONVERT(INT, 27);

다음으로, 스키마 바인딩 된 뷰에서 클러스터 된 인덱스를 만들었습니다.이 뷰는 계산 된 열의 값을 포함하여 뷰에 저장된 값을 유지하는 효과가 있습니다.

CREATE UNIQUE CLUSTERED INDEX IX_PersistedViewTest
ON dbo.PersistedViewTest_View(PersistedViewTest_ID);
GO

테스트 데이터를 테이블에 삽입하십시오.

INSERT INTO dbo.PersistedViewTest (SomeData)
SELECT o.name + o1.name + o2.name
FROM sys.objects o
    CROSS JOIN sys.objects o1
    CROSS JOIN sys.objects o2;

보기에서 통계 항목 및 색인을 작성하십시오.

CREATE STATISTICS ST_PersistedViewTest_View
ON dbo.PersistedViewTest_View(TestComputedColumn)
WITH FULLSCAN;

CREATE INDEX IX_PersistedViewTest_View_TestComputedColumn
ON dbo.PersistedViewTest_View(TestComputedColumn);

SELECT지속 열 있는 테이블에 대해 명령문을 수행 하면 쿼리 최적화 프로그램이 적절하다고 판단하는 경우 지속 뷰를 자동으로 사용할 수 있습니다 .

SELECT pv.PersistedViewTest_ID
    , pv.TestComputedColumn
FROM dbo.PersistedViewTest pv
WHERE pv.TestComputedColumn = CONVERT(INT, 26)

위 쿼리에 대한 실제 실행 계획은 쿼리 최적화 프로그램이 지속적보기를 사용하여 결과를 반환하도록 선택한 것을 보여줍니다.

여기에 이미지 설명을 입력하십시오

WHERE위 의 절 에서 명시적인 변환을 발견했을 수도 있습니다 . 이를 CONVERT(INT, 26)통해 쿼리 최적화 프로그램은 통계 개체를 올바르게 사용하여 쿼리에서 반환 할 행 수를 추정 할 수 있습니다. 로 쿼리를 작성하면 쿼리 WHERE pv.TestComputedColumn = 26최적화 프로그램은 실제로 26 개 행이TINY INT ; 이로 인해 SQL Server가 지속 뷰를 사용하지 않을 수 있습니다. 암시 적 변환은 매우 고통 스러울 수 있으며 비교 및 ​​조인에 올바른 데이터 형식을 일관되게 사용해야합니다.

물론 스키마 바인딩을 사용하여 발생하는 모든 표준 "gotchas"는 위 시나리오에 적용됩니다. 모든 시나리오에서이 대안을 사용하지 못할 수 있습니다. 예를 들어, 뷰에서 스키마 바인딩을 먼저 제거하지 않고는 더 이상 기본 테이블을 수정할 수 없습니다. 그러기 위해서는 뷰에서 클러스터형 인덱스를 제거해야합니다.

SQL Server Enterprise Edition이없는 경우 쿼리 최적화 프로그램은 WITH (NOEXPAND)힌트를 사용하여 뷰를 직접 참조하지 않는 쿼리에 대해 지속 뷰를 자동으로 사용하지 않습니다 . 비 Enterprise Edition 버전에서 지속보기를 사용하면 얻을 수있는 이점을 얻으려면 위의 쿼리를 다음과 같이 다시 작성해야합니다.

SELECT pv.PersistedViewTest_ID
    , pv.TestComputedColumn
FROM dbo.PersistedViewTest_View pv WITH (NOEXPAND)
WHERE pv.TestComputedColumn = CONVERT(INT, 26)

위의 Enterprise Edition 제한을 지적한 Ian Ringrose 와 힌트를 위한 Paul White 에게 감사드립니다 (NOEXPAND).

Paul의 대답 에는 지속 뷰와 관련하여 쿼리 최적화 프로그램에 대한 흥미로운 세부 정보가 있습니다.


이 문제를 해결하려면 클러스터 된 인덱스와 비 클러스터형 인덱스가 모두 뷰에서 만들어집니다. 어떤 이유로 클러스터되지 않은 인덱스를 클러스터 된 인덱스에 사용해야합니까? 아니면 비 클러스터형 인덱스가 더 성능이 좋습니까? 쿼리에 클러스터형 인덱스가 사용 된 경우 통계에 어떤 내용이 표시됩니까?
밥 브라이언

흥미로운 질문 인 @BobBryan-클러스터 인덱스는 실제로 고유 인덱스 일 필요는 없지만 뷰를 유지하려면 뷰를 유지해야합니다. TestComputedColumn대신 다른 열에 뷰의 클러스터형 인덱스를 만들 수있었습니다 . 그러나 클러스터 된 인덱스에는 테이블 / 뷰에 대한 모든 데이터가 포함되어 있기 때문에 단조 증가하는 숫자를 클러스터링 키로 사용하는 것이 좋습니다. 참고로, 나는 그 가정을 실제로 테스트하지 않았으며, 실제로 일부 변형의 재현에서는 올바르지 않을 수 있습니다.
Max Vernon

비 클러스터형 인덱스는 커버링 인덱스가 아니므로 뷰 또는 기본 테이블에서 열을 필터링, 조인 또는 반환하는 쿼리는 기본 테이블 또는 테이블에 대해 키 조회 작업을 수행해야합니다. 보기. 실제 시나리오의 경우 더 나은 성능을 염두에두고 제한된 답변 범위를 설명 할 수 있습니다.
Max Vernon

4

from Create Index및 해당 where절에서는 불가능합니다.

어디

색인에 포함 할 행을 지정하여 필터링 된 색인을 작성합니다. 필터링 된 인덱스는 테이블에서 비 클러스터형 인덱스 여야합니다. 필터링 된 인덱스에서 데이터 행에 대한 필터링 된 통계를 작성합니다.

필터 술어는 단순 비교 논리를 사용하며 계산 열, UDT 열, 공간 데이터 유형 열 또는 hierarchyID 데이터 유형 열을 참조 할 수 없습니다. NULL 리터럴을 사용한 비교는 비교 연산자와 함께 사용할 수 없습니다. 대신 IS NULL 및 IS NOT NULL 연산자를 사용하십시오.

출처 : MSDN


3
  • 필터링 된 인덱스를 넣기 위해 계산되지 않은 열이 필요합니다.
  • 해당 열로 이동하려면 값을 계산해야합니다.

열을 계산하기 전에 행을 변경하거나 삽입 할 때마다 트리거 를 사용하여 열 값을 계산했습니다.

(트리거를 사용하여 두 번째 테이블에서 항목의 PK를 삽입 / 제거한 다음 쿼리에 사용할 수도 있습니다.)


3

이것은 Max Vernon의 작업 개선을위한 시도 입니다. 그의 솔루션에서는 뷰와 통계 개체에 2 개의 인덱스를 사용하는 것이 좋습니다.

첫 번째 인덱스는 클러스터링되는데, 실제로 테이블에 클러스터되지 않은 인덱스와 달리 뷰에 클러스터되지 않은 인덱스를 만들려고 시도하면 먼저 클러스터 된 인덱스가 없어도 오류가 발생합니다.

두 번째 인덱스는 비 클러스터형 인덱스이며 쿼리 뒤에 인덱스로 사용됩니다. 그의 답변의 의견 섹션에서 클러스터되지 않은 인덱스 대신 클러스터형 인덱스를 사용하면 어떻게 될지 물었습니다.

다음 분석은이 질문에 답하려고합니다.

뷰에서 클러스터되지 않은 인덱스를 생성하지 않는 것을 제외하고는 그의 동일한 코드를 사용하고 있습니다.

또한 통계 개체를 만들지 않습니다. SSMS (SQL Server Management Studio)를 따라 아래 코드를 입력하는 경우 오류처럼 보이는 빨간 구불 구불 한 줄이 나타날 수 있습니다. 이러한 오류는 (아마도) 오류는 아니지만 인텔리전스 관련 문제와 관련이 있습니다.

인텔리전스를 비활성화하거나 오류를 무시하고 명령을 실행할 수 있습니다. 오류없이 완료해야합니다.

-- Create the test table that uses a computed column.
USE tempdb;
CREATE TABLE dbo.PersistedViewTest
(
    PersistedViewTest_ID INT NOT NULL
    CONSTRAINT PK_PersistedViewTest
    PRIMARY KEY CLUSTERED
    IDENTITY(1,1)
    , SomeData VARCHAR(2000) NOT NULL
    , TestComputedColumn AS (PersistedViewTest_ID - 1) PERSISTED
);
GO

-- Insert some test data into the table.
INSERT INTO dbo.PersistedViewTest (SomeData)
SELECT o.name + o1.name + o2.name
FROM sys.objects o
    CROSS JOIN sys.objects o1
    CROSS JOIN sys.objects o2;
GO

다음 쿼리가 테이블에 대해 실행 된 후 다음 실행 계획 (보기 / 인덱스보기 없음)이 생성됩니다.

SELECT pv.PersistedViewTest_ID, pv.TestComputedColumn
FROM dbo.PersistedViewTest pv
WHERE pv.TestComputedColumn = CONVERT(INT, 26)
GO

여기에 이미지 설명을 입력하십시오

이것은 비교할 기준을 제공합니다. 쿼리가 완료된 후 통계 개체 (_WA_Sys_00000003_1FCDBCEB)가 생성되었습니다. 클러스터 된 테이블 인덱스를 만들 때 PK_PersistedViewTest 통계 개체가 생성되었습니다.

다음으로 해당보기에서 필터링 된보기 및 클러스터 된 인덱스가 작성됩니다.

-- Create filtered view on the computed column.
CREATE VIEW dbo.PersistedViewTest_View
WITH SCHEMABINDING
AS
SELECT PersistedViewTest_ID, SomeData, TestComputedColumn
FROM dbo.PersistedViewTest
WHERE TestComputedColumn < CONVERT(INT, 27);
GO

-- Create unique clustered index to persist the values, including the computed column.
CREATE UNIQUE CLUSTERED INDEX IX_PersistedViewTest
ON dbo.PersistedViewTest_View(PersistedViewTest_ID);
GO

이제 쿼리를 다시 실행 해 보겠습니다.

SELECT pv.PersistedViewTest_ID, pv.TestComputedColumn
FROM dbo.PersistedViewTest_View pv
WHERE pv.TestComputedColumn = CONVERT(INT, 26)
GO

새로운 실행 계획은 다음과 같습니다.

여기에 이미지 설명을 입력하십시오

새 계획을 믿으려면 해당 뷰에 뷰와 클러스터 된 인덱스를 추가 한 후 쿼리 실행에 필요한 시간이 두 배로 늘어난 것으로 나타납니다. 또한 쿼리가 실행 된 후 새 인덱스를 지원하기 위해 테이블에있는 쿼리와 다른 새 통계 개체가 만들어지지 않았습니다.

쿼리 계획은 비 클러스터형 인덱스를 만드는 것이 쿼리 성능을 향상시키는 데 상당히 도움이 될 것이라고 제안합니다. 그렇다면 원하는 성능 향상을 달성하기 전에 비 클러스터형 인덱스를 뷰에 추가해야합니까? 마지막으로 시도해야 할 것이 있습니다. "WITH NOEXPAND"옵션을 사용하도록 조회를 수정하십시오.

SELECT pv.PersistedViewTest_ID, pv.TestComputedColumn
FROM dbo.PersistedViewTest_View pv WITH (NOEXPAND)
WHERE pv.TestComputedColumn = CONVERT(INT, 26)
GO

결과는 다음과 같은 쿼리 계획입니다.

여기에 이미지 설명을 입력하십시오

이 실행 계획은 Max Vernon의 답변에 제공된 비 클러스터형 인덱스로 생성 된 것과 매우 유사합니다. 그러나 이것은 하나의 클러스터되지 않은 인덱스와 하나의 통계 개체로 이루어집니다.

인덱스 된 뷰를 올바르게 사용하려면 NOEXPAND 옵션을 Express 및 표준 버전의 SQL Server와 함께 사용해야합니다. Paul White는 NOEXPAND 옵션 사용의 이점에 대해 설명 하는 훌륭한 기사 를 제공합니다. 또한 옵티마이 저가 뷰 인덱스에서 제공하는 고유성 보장을 보장하기 위해이 옵션을 Enterprise Edition과 함께 사용할 것을 권장 합니다.

위의 분석은 SQL Sever 2014의 익스프레스 에디션으로 수행되었습니다. 또한 SQL Server 2016의 개발자 에디션에서도 시도했습니다. NOEXPAND 옵션은 성능 향상을 위해 개발 에디션에 필요하지 않은 것으로 보이지만 여전히 권장됩니다 .

5 개월 전에 Microsoft는 개발자 에디션을 무료 로 만들었습니다 . 라이센스는 개발 만 사용하도록 제한하므로 프로덕션 환경에서는 데이터베이스를 사용할 수 없습니다. 따라서 메모리 최적화 테이블, 암호화, R 등을 테스트하려는 경우 더 이상 라이센스 없음 변명이 없습니다. 며칠 전에 SQL Server 2014 Express와 함께 문제없이 컴퓨터에 성공적으로 설치했습니다.

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