탐색하고 파티션 된 테이블에서 스캔해야합니다…


22

Itzik Ben-Gan의 PCMag에서이 기사를 읽었습니다 .

파트 I을 찾아서 스캔해야 함 : 옵티마이 저가 최적화하지 않고 파트 II를 탐색 할 때
: 오름차순 키

현재 모든 파티션 된 테이블에 "Grouped Max"문제가 있습니다. Itzik Ben-Gan이 max (ID)를 얻기 위해 제공 한 트릭을 사용 하지만 때로는 실행되지 않습니다.

DECLARE @MaxIDPartitionTable BIGINT
SELECT  @MaxIDPartitionTable = ISNULL(MAX(IDPartitionedTable), 0)
FROM    ( SELECT    *
          FROM      ( SELECT    partition_number PartitionNumber
                      FROM      sys.partitions
                      WHERE     object_id = OBJECT_ID('fct.MyTable')
                                AND index_id = 1
                    ) T1
                    CROSS APPLY ( SELECT    ISNULL(MAX(UpdatedID), 0) AS IDPartitionedTable
                                  FROM      fct.MyTable s
                                  WHERE     $PARTITION.PF_MyTable(s.PCTimeStamp) = PartitionNumber
                                            AND UpdatedID <= @IDColumnThresholdValue
                                ) AS o
        ) AS T2;
SELECT @MaxIDPartitionTable 

나는이 계획을 얻는다

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

그러나 45 분 후에 읽은 내용을보십시오

reads          writes   physical_reads
12,949,127        2       12,992,610

내가 나가는 것 sp_whoisactive.

일반적으로 꽤 빨리 실행되지만 오늘날은 아닙니다.

편집 : 파티션이있는 테이블 구조 :

CREATE PARTITION FUNCTION [MonthlySmallDateTime](SmallDateTime) AS RANGE RIGHT FOR VALUES (N'2000-01-01T00:00:00.000', N'2000-02-01T00:00:00.000' /* and many more */)
go
CREATE PARTITION SCHEME PS_FctContractualAvailability AS PARTITION [MonthlySmallDateTime] TO ([Standard], [Standard])
GO
CREATE TABLE fct.MyTable(
    MyTableID BIGINT IDENTITY(1,1),
    [DT1TurbineID] INT NOT NULL,
    [PCTimeStamp] SMALLDATETIME NOT NULL,
    Filler CHAR(100) NOT NULL DEFAULT 'N/A',
    UpdatedID BIGINT NULL,
    UpdatedDate DATETIME NULL
CONSTRAINT [PK_MyTable] PRIMARY KEY CLUSTERED 
(
    [DT1TurbineID] ASC,
    [PCTimeStamp] ASC
) WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, DATA_COMPRESSION = ROW) ON [PS_FctContractualAvailability]([PCTimeStamp])
) ON [PS_FctContractualAvailability]([PCTimeStamp])

GO

CREATE UNIQUE NONCLUSTERED INDEX [IX_UpdatedID_PCTimeStamp] ON [fct].MyTable
(
    [UpdatedID] ASC,
    [PCTimeStamp] ASC
)
INCLUDE (   [UpdatedDate]) 
WHERE ([UpdatedID] IS NOT NULL)
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, DATA_COMPRESSION = ROW) ON [PS_FctContractualAvailability]([PCTimeStamp])
GO

답변:


28

기본적인 문제는 Index Seek 뒤에 Top 연산자가 없다는 것입니다. 이것은 일반적으로 탐색이 행에 대해 올바른 순서로 행을 리턴 할 때 도입되는 최적화입니다 MIN\MAX.

이 최적화는 최소 / 최대 행이 오름차순 또는 내림차순의 첫 번째 행이라는 사실을 이용합니다. 옵티마이 저가이 최적화를 파티션 된 테이블에 적용하지 못할 수도 있습니다. 잊었다.

어쨌든 요점은이 변환이 없으면 실행 계획 S.UpdatedID <= @IDColumnThresholdValue은 파티션 당 원하는 행 하나가 아니라 파티션 당 규정 된 모든 행을 처리하게 된다는 것입니다.

질문에 테이블, 인덱스 또는 파티션 정의를 제공하지 않았으므로 더 구체적으로 말할 수 없습니다. 색인이 그러한 변환을 지원하는지 확인해야합니다. 더 많은 이하 동등하게, 당신은 또한 표현할 수 MAXA와를 TOP (1) ... ORDER BY UpdatedID DESC.

이로 인해 정렬 ( TopN 정렬 포함 )이 발생하면 색인이 도움이되지 않는 것입니다. 예를 들면 다음과 같습니다.

SELECT
    @MaxIDPartitionTable = ISNULL(MAX(T2.IDPartitionedTable), 0)
FROM    
( 
    SELECT
        O.IDPartitionedTable
    FROM      
    ( 
        SELECT
            P.partition_number AS PartitionNumber
        FROM sys.partitions AS P
        WHERE 
            P.[object_id] = OBJECT_ID(N'fct.MyTable', N'U')
            AND P.index_id = 1
    ) AS T1
    CROSS APPLY 
    (    
        SELECT TOP (1) 
            S.UpdatedID AS IDPartitionedTable
        FROM fct.MyTable AS S
        WHERE
            $PARTITION.PF_MyTable(S.PCTimeStamp) = T1.PartitionNumber
            AND S.UpdatedID <= @IDColumnThresholdValue
        ORDER BY
            S.UpdatedID DESC
    ) AS O
) AS T2;

이것이 생성해야하는 계획 형태는 다음과 같습니다.

원하는 계획 형태

색인 검색 아래의 상단을 확인하십시오. 이는 파티션 당 하나의 행으로 처리를 제한합니다.

또는 임시 테이블을 사용하여 파티션 번호를 보유하십시오.

CREATE TABLE #Partitions
(
    partition_number integer PRIMARY KEY CLUSTERED
);

INSERT #Partitions
    (partition_number)
SELECT
    P.partition_number AS PartitionNumber
FROM sys.partitions AS P
WHERE 
    P.[object_id] = OBJECT_ID(N'fct.MyTable', N'U')
    AND P.index_id = 1;

SELECT
    @MaxIDPartitionTable = ISNULL(MAX(T2.UpdatedID), 0)
FROM #Partitions AS P
CROSS APPLY 
(
    SELECT TOP (1) 
        S.UpdatedID
    FROM fct.MyTable AS S
    WHERE
        $PARTITION.PF_MyTable(S.PCTimeStamp) = P.partition_number
        AND S.UpdatedID <= @IDColumnThresholdValue
    ORDER BY
        S.UpdatedID DESC
) AS T2;

DROP TABLE #Partitions;

참고 : 쿼리에서 시스템 테이블에 액세스하면 병렬 처리가 방지됩니다. 이것이 중요한 경우, 임시 테이블에 파티션 번호를 구체화 한 다음 그 번호를 고려하십시오 APPLY. 병렬 처리는 일반적 으로이 패턴 (정확한 색인 작성)에서 도움이되지 않지만 언급하지 않는 것이 좋습니다.

참고 2 : 파티션 된 오브젝트의 집계 및 Top에 대한 내장 지원을 요청 하는 활성 Connect 항목이MIN\MAX 있습니다.

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