증분 업데이트 후 통계가 사라짐


21

증분 통계를 사용하는 큰 파티션 된 SQL Server 데이터베이스가 있습니다. 모든 인덱스가 분할되어 정렬됩니다. 파티션별로 파티션을 온라인으로 재구성하려고하면 인덱스가 재구성 된 후 모든 통계가 사라집니다.

다음은 AdventureWorks2014 데이터베이스를 사용하여 SQL Server 2014에서 문제를 복제하는 스크립트입니다.

--Example against AdventureWorks2014 Database

CREATE PARTITION FUNCTION TransactionRangePF1 (DATETIME)
AS RANGE RIGHT FOR VALUES 
(
   '20130501', '20130601', '20130701', '20130801', 
   '20130901', '20131001', '20131101', '20131201', 
   '20140101', '20140201', '20140301'
);
GO

CREATE PARTITION SCHEME TransactionsPS1 AS PARTITION TransactionRangePF1 TO 
(
  [PRIMARY], [PRIMARY], [PRIMARY], [PRIMARY], [PRIMARY], 
  [PRIMARY], [PRIMARY], [PRIMARY], [PRIMARY], [PRIMARY], 
  [PRIMARY], [PRIMARY], [PRIMARY]
);
GO

CREATE TABLE dbo.TransactionHistory 
(
  TransactionID        INT      NOT NULL, -- not bothering with IDENTITY here
  ProductID            INT      NOT NULL,
  ReferenceOrderID     INT      NOT NULL,
  ReferenceOrderLineID INT      NOT NULL DEFAULT (0),
  TransactionDate      DATETIME NOT NULL DEFAULT (GETDATE()),
  TransactionType      NCHAR(1) NOT NULL,
  Quantity             INT      NOT NULL,
  ActualCost           MONEY    NOT NULL,
  ModifiedDate         DATETIME NOT NULL DEFAULT (GETDATE()),
  CONSTRAINT CK_TransactionType 
    CHECK (UPPER(TransactionType) IN (N'W', N'S', N'P'))
) 
ON TransactionsPS1 (TransactionDate);


INSERT INTO dbo.TransactionHistory
SELECT * FROM Production.TransactionHistory
--  SELECT * FROM sys.partitions
--  WHERE object_id = OBJECT_ID('dbo.TransactionHistory');

CREATE NONCLUSTERED INDEX IDX_ProductId ON dbo.TransactionHistory (ProductId) 
  WITH (DATA_COMPRESSION = ROW, STATISTICS_INCREMENTAL=ON)  
  ON TransactionsPS1 (TransactionDate)

DBCC SHOW_STATISTICS('dbo.TransactionHistory', IDX_ProductId);
PRINT 'Stats are avialable'  

ALTER INDEX [IDX_ProductId] ON [dbo].[TransactionHistory] REBUILD 
  PARTITION = 9 WITH (ONLINE = ON , DATA_COMPRESSION = ROW)

PRINT 'After online index rebuild by partition stats are now gone'
DBCC SHOW_STATISTICS('dbo.TransactionHistory', IDX_ProductId);

PRINT 'Rebuild the stats with a rebuild for all paritions (this works)' 
ALTER INDEX [IDX_ProductId] ON [dbo].[TransactionHistory] REBUILD 
  PARTITION = ALL WITH (ONLINE = ON , DATA_COMPRESSION = ROW, 
  STATISTICS_INCREMENTAL = ON)

PRINT 'Stats are back'
DBCC SHOW_STATISTICS('dbo.TransactionHistory', IDX_ProductId);

PRINT 'Works correctly for an offline rebuild by partition'
ALTER INDEX [IDX_ProductId] ON [dbo].[TransactionHistory] REBUILD 
  PARTITION = 9 WITH (ONLINE = OFF , DATA_COMPRESSION = ROW)

    --stats still there  
DBCC SHOW_STATISTICS('dbo.TransactionHistory', IDX_ProductId);

ALTER INDEX [IDX_ProductId] ON [dbo].[TransactionHistory] REBUILD 
  PARTITION = 9 WITH (ONLINE = ON , DATA_COMPRESSION = ROW)

DBCC SHOW_STATISTICS('dbo.TransactionHistory', IDX_ProductId);
PRINT' stats are gone!!!!!!'

표시된 것처럼 인덱스에 대한 모든 통계를 잃지 않으면 서 온라인 파티션으로 인덱스를 다시 작성할 수 없습니다. 이것은 우리에게 중요한 유지 관리 문제입니다. 통계 증분 옵션이 단일 인덱스 재 구축 구문의 일부이거나 온라인 옵션이 오프라인 옵션과 마찬가지로 올바르게 처리해야하는 것으로 보입니다.

내가 빠진 것이 있으면 알려주십시오.

업데이트 :

증분 통계가 필요한 한 : 날짜가 아닌 내부 고객 ID로 파티셔닝합니다. 따라서 새로운 클라이언트를 가져 오면 (대규모의 데이터로드) 파티션 통계를 간단히 업데이트하고이 새로운 고객에 대한 추악한 계획을 신속하게 피할 수 있습니다. 나는 그것을 버그로 Microsoft에 제출하고 그들이 무엇을 말해야하는지보고 그 파티션에 대한 통계를 다시 샘플링하는 솔루션과 함께 갈 것이라고 생각합니다.

버그 보고서 연결 :

증분 통계를 사용하여 온라인 인덱스를 재 구축 한 후 통계가 사라짐

업데이트 : Microsoft는 버그임을 확인했습니다.


1
업데이트 : Microsoft는 오늘 아침이 버그가 SQL 2014의 다음 CU 업데이트에서 수정 될 것이라는 이메일을 보냈습니다.
JasonR

어떤 CU를 수정했는지 또는 해당 전자 메일에보고 한 KB는 무엇입니까? 그것이 언제 고쳐 졌는지 보려고합니다.
mbourgon

1
SQL Server 2014 SP1 용 CU 9의 일부인 VSTS 버그 번호 8046729KB 문서 번호 3194959인지 확인하십시오. KB 링크는 여기에 있습니다 .
JasonR

예, 그것은 모양이 좋았습니다. 지난 달 2016SP1에서 수정되었습니다. 많은 감사합니다!
mbourgon

수정 : 2016 SP1 CU2에서 수정되었습니다. 2016 SP1 CU1에서 발생합니다.
mbourgon

답변:


17

확실하지가 버그의 경우 자체 하지만 확실히 흥미로운 사건이다. 온라인 파티션 재 구축은 SQL Server 2014의 새로운 기능이므로 이에 따라 일부 내부 구성 요소가있을 수 있습니다.

여기 당신을위한 최고의 설명이 있습니다. 증분 통계는 엔진이 통계 페이지를 병합 할 때 샘플링 된 분포가 비슷하다는 것을 확신 할 수 있도록 모든 파티션을 동일한 속도로 샘플링해야합니다. REBUILD100 % 샘플링 속도로 데이터를 샘플링해야합니다. 파티션 9의 100 % 샘플 속도가 항상 나머지 파티션의 정확한 샘플 속도 일 것이라는 보장은 없습니다. 이 때문에 엔진이 샘플을 병합 할 수없고 빈 통계 블롭으로 끝납니다. 그러나 통계 개체는 여전히 존재합니다.

select 
    check_time = sysdatetime(),                         
    schema_name = sh.name,
    table_name = t.name,
    stat_name = s.name,
    index_name = i.name,
    stats_column = index_col(quotename(sh.name)+'.'+quotename(t.name),s.stats_id,1),
    s.stats_id,
    s.has_filter,                       
    s.is_incremental,
    s.auto_created,
    sp.last_updated,    
    sp.rows,
    sp.rows_sampled,                        
    sp.unfiltered_rows,
    modification_counter 
from sys.stats s 
join sys.tables t 
    on s.object_id = t.object_id
join sys.schemas sh
    on t.schema_id = sh.schema_id
left join sys.indexes i 
    on s.object_id = i.object_id
    and s.name = i.name
outer apply sys.dm_db_stats_properties(s.object_id, s.stats_id) sp
where t.name = 'TransactionHistory' and sh.name = 'dbo'

여러 방법으로 얼룩을 채울 수 있습니다.

UPDATE STATISTICS dbo.TransactionHistory (IDX_ProductId) WITH RESAMPLE;

또는

UPDATE STATISTICS dbo.TransactionHistory (IDX_ProductId) WITH RESAMPLE ON PARTITIONS (9);

또는 해당 객체를 사용하여 쿼리 계획의 첫 번째 컴파일에서 AutoStats가 업데이트 될 때까지 기다릴 수 있습니다.

-- look at my creative query
select * 
from dbo.TransactionHistory
where TransactionDate = '20140101';

이 모든 것을 말해 두 겠는데, 에린 Stellato에 의해이 계몽 후 무슨 하이라이트는 증가 통계의 주요 부족으로 인식 할 수 온다. 파티션 레벨 데이터는 쿼리 계획 생성에서 옵티마이 저가 사용하지 않으므로 증분 통계의 추정되는 이점을 줄입니다. 그러면 증분 통계의 현재 이점은 무엇입니까? 기본 유틸리티가 기존 통계보다 더 큰 비율로 더 큰 테이블을 더 일관되게 샘플링 할 수있는 능력에 있다고 생각합니다.

예제를 사용하여 다음과 같이 보입니다.

set statistics time on;

update statistics dbo.TransactionHistory(IDX_ProductId)
with fullscan;

--SQL Server Execution Times:
--  CPU time = 94 ms,  elapsed time = 131 ms.


update statistics dbo.TransactionHistory(IDX_ProductId)
with resample on partitions(2);

 --SQL Server Execution Times:
 --  CPU time = 0 ms,  elapsed time = 5 ms.

drop index IDX_ProductId On dbo.TransactionHistory;

CREATE NONCLUSTERED INDEX IDX_ProductId ON dbo.TransactionHistory (ProductId) 
  WITH (DATA_COMPRESSION = ROW)  
  ON [PRIMARY]

update statistics dbo.TransactionHistory(IDX_ProductId)
with fullscan;

 --SQL Server Execution Times:
 --  CPU time = 76 ms,  elapsed time = 66 ms.

증분 통계에 대한 전체 스캔 통계 업데이트 비용은 131ms입니다. 파티션이 정렬되지 않은 통계에 대한 전체 스캔 통계 업데이트는 66ms입니다. 정렬되지 않은 통계는 개별 통계 페이지를 기본 히스토그램으로 다시 병합 할 때 발생하는 오버 헤드로 인해 가장 느립니다.. 그러나 파티션 정렬 통계 개체를 사용하여 하나의 파티션을 업데이트하고 5ms 내에 기본 히스토그램 얼룩으로 다시 병합 할 수 있습니다. 따라서이 시점에서 증분 통계량을 가진 관리자는 결정에 직면하게됩니다. 기존의 업데이트 만 필요로했던 파티션 만 업데이트하여 전체 통계 유지 보수 시간을 줄이거 나 이전 유지 보수 기간과 동일한 기간에 더 많은 행을 샘플링 할 수 있도록 더 높은 샘플 속도로 실험 할 수 있습니다. 전자는 유지 관리 기간에 호흡 실을 허용하고 후자 는 매우 큰 테이블의 통계를보다 정확한 통계를 기반으로 쿼리가 더 나은 계획을 얻는 곳으로 푸시 할 수 있습니다 . 이것은 보증이 아니며 마일리지가 다를 수 있습니다.

독자는이 테이블에서 66ms가 고통스러운 통계 업데이트 시간이 아니라는 것을 알 수 있으므로 stackexchange 데이터 세트에서 테스트를 설정하려고했습니다. 최근에 다운로드 한 덤프에 6,418,608 개의 게시물 (2012 년의 StackOverflow 게시물 및 모든 게시물 제외-데이터 오류)이 있습니다.

나는 [CreationDate]... 데모 때문에 데이터를 분할했습니다 .

다음은 일부 표준 시나리오 (100 %-인덱스 재 구축, 기본-통계 자동 업데이트 또는 UPDATE STATISTICS지정된 샘플 속도가없는 경우)에 대한 타이밍입니다 .

  • Fullscan을 사용하여 비 증분 통계를 만듭니다. CPU 시간 = 23500ms, 경과 시간 = 22521ms.
  • Fullscan으로 증분 통계 생성 : CPU 시간 = 20406ms, 경과 시간 = 15413ms
  • 기본 샘플 속도로 비 증분 통계 업데이트 : CPU 시간 = 406ms, 경과 시간 = 408ms
  • 기본 샘플 속도로 증분 통계 업데이트 : CPU 시간 = 453ms, 경과 시간 = 507ms

기본 시나리오보다 더 정교하고 유지 보수 시간을 합리적으로 유지하면서 필요한 계획을 얻는 데 필요한 최소 속도 인 10 % 샘플 속도를 결정했다고 가정 해 보겠습니다.

  • 비 증분 통계를 샘플 10 %로 업데이트합니다. CPU 시간 = 2344ms, 경과 시간 = 2441ms.
  • CPU 시간 = 2344ms, 경과 시간 = 2388ms : 샘플 10 %로 증분 통계 업데이트

지금까지 증분 통계를 사용하면 분명한 이점이 없습니다. 그러나 문서화되지 않은 sys.dm_db_stats_properties_internal() DMV (아래)를 활용하면 업데이트 할 파티션에 대한 통찰력을 얻을 수 있습니다. 파티션 3의 데이터를 변경했으며 들어오는 쿼리에 대한 통계를 최신 상태로 유지하려고합니다. 옵션은 다음과 같습니다.

  • 기본적으로 비 증분 업데이트 (자동 통계 업데이트의 기본 동작) : 408ms
  • 비 증분을 10 % : 2441ms로 업데이트합니다.
  • 증분 통계 업데이트, 재 샘플로 파티션 3 (10 %-정의 된 샘플 속도) : CPU 시간 = 63ms, 경과 시간 = 63ms.

여기서 결정을 내려야합니다. 우리는 63ms의 승리를합니까? 파티션 기반 통계 업데이트 또는 샘플링 속도가 더 높습니까? 증분 통계에서 샘플링의 초기 적중을 50 %로 기꺼이 감수한다고 가정 해 보겠습니다

  • 증분 통계를 50 %로 업데이트 : 경과 시간 = 16840ms
  • 증분 통계 업데이트, 재 샘플이있는 파티션 3 (50 %-새 업데이트 시간) : 경과 시간 = 295ms

우리는 훨씬 더 많은 데이터를 샘플링 할 수 있으며, 아마도 파티션 레벨 통계를 사용하지 않더라도 데이터에 대해 더 나은 추측을 할 수 있도록 옵티 마이저를 설정할 수 있습니다. 증분 통계.

그래도 알아 두어야 할 마지막 재미있는 일입니다. 동기 통계 업데이트는 어떻습니까? 자동 통계가 시작 되더라도 50 % 샘플 속도가 유지됩니까?

파티션 3에서 데이터를 삭제하고 CreationDate에서 쿼리를 실행하고 확인한 다음 아래의 동일한 쿼리로 속도를 확인했습니다. 50 % 샘플 속도가 유지되었습니다.

간단히 말해, 증분 통계는 적절한 양의 사고와 초기 설정 작업에 유용한 도구가 될 수 있습니다. 그러나 해결하려는 문제를 알고 있어야하며 적절하게 해결해야합니다. 카디널리티 예상치가 나쁜 경우 전략적인 샘플링 속도와 일부 투자 된 개입으로 더 나은 계획을 얻을 있습니다. 그러나 사용되는 히스토그램은 파티션 수준 정보가 아니라 병합 된 단일 통계 페이지이므로 이점의 일부만 얻을 수 있습니다. 유지 관리 기간에 어려움이 있다면 증분 통계가 도움이 될 수 있지만 높은 유지 관리 개입 프로세스를 설정해야 할 수도 있습니다. 어쨌든:

  • 기본 테이블과 파티션 정렬되지 않은 인덱스로 작성된 통계.
  • AlwaysOn 읽기 가능 보조 데이터베이스에서 작성된 통계.
  • 읽기 전용 데이터베이스에서 작성된 통계.
  • 필터링 된 인덱스에서 생성 된 통계.
  • 뷰에서 생성 된 통계.
  • 내부 테이블에서 작성된 통계.
  • 공간 인덱스 또는 XML 인덱스로 작성된 통계.

이것이 도움이되기를 바랍니다.

select 
    sysdatetime(),                          
    schema_name = sh.name,
    table_name = t.name,
    stat_name = s.name,
    index_name = i.name,
    leading_column = index_col(quotename(sh.name)+'.'+quotename(t.name),s.stats_id,1),
    s.stats_id,
    parition_number = isnull(sp.partition_number,1),
    s.has_filter,                       
    s.is_incremental,
    s.auto_created,
    sp.last_updated,    
    sp.rows,
    sp.rows_sampled,                        
    sp.unfiltered_rows,
    modification_counter = coalesce(sp.modification_counter, n1.modification_counter) 
from sys.stats s 
join sys.tables t 
    on s.object_id = t.object_id
join sys.schemas sh
    on t.schema_id = sh.schema_id
left join sys.indexes i 
    on s.object_id = i.object_id
        and s.name = i.name
cross apply sys.dm_db_stats_properties_internal(s.object_id, s.stats_id) sp
outer apply sys.dm_db_stats_properties_internal(s.object_id, s.stats_id) n1
where n1.node_id = 1
    and (
            (is_incremental = 0)
               or
            (is_incremental = 1 and sp.partition_number is not null)
         )
    and t.name = 'Posts'
    and s.name like 'st_posts%'
order by s.stats_id,isnull(sp.partition_number,1)
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.