KB3067257 - FIX: SQL Server 2014에서 클러스터형 columnstore 인덱스 쿼리의 일부 결과 발생

적용 대상
SQL Server 2014 Developer - duplicate (do not use) SQL Server 2014 Enterprise - duplicate (do not use) SQL Server 2014 Standard - duplicate (do not use)

이 문서에서는 Microsoft SQL Server 2014에서 클러스터형 columnstore 인덱스를 쿼리하는 동안 발생하는 문제에 대해 설명합니다. 이 문서에서는 이 문제에 대한 해결 방법을 제공합니다 .

요약​​

Microsoft SQL Server 2014에서 클러스터형 columnstore 인덱스를 검색하는 쿼리를 사용할 때 드물게 부분적인 쿼리 결과가 표시될 수 있습니다.

이 문제는 다음 작업을 실행하면 발생합니다.

1단계

Transact-SQL 문[INSERT 또는 BULK-INSERT]은 클러스터형 columnstore 인덱스가 있는 테이블에 데이터를 삽입합니다. 이 작업 중에는 다음 조건이 적용됩니다.

  • Transact-SQL 문이 행 그룹 임계값에 도달하면 세그먼트 S1이 있는 행 그룹 R1을 닫습니다.
  • 세그먼트 S1은 로컬 사전 D1을 가리킵니다.
  • 명령문은 새 행 그룹 R2에 행을 계속 삽입합니다.
  • rowgroup R1이 닫히면 로컬 사전 D1도 닫을 필요가 없습니다. 사전 D1에 사용 가능한 공간이 있는 경우 열어 두고 새 행 그룹 R2에 다시 사용할 수 있습니다.

2단계

Transact-SQL 문이 비정상적으로 종료되거나 새 행 그룹 R2를 닫기 전에 취소되면 다음 조건이 적용됩니다.

  • 열 저장소 메타데이터 변경은 외부 트랜잭션과 독립적으로 커밋되는 하위 트랜잭션에서 발생합니다.
  • 이 시점에서 rowgroup R1은 시스템 테이블에서 "구성 중" 또는 보이지 않는 상태로 유지되며 세그먼트 S1은 사전 D1을 참조합니다.
  • 사전 D1에 대한 시스템 테이블에 만들어진 행이 없습니다. 이는 Transact-SQL 문이 기존 행을 닫을 기회가 없기 때문입니다. 따라서 기존 행은 유지됩니다.

3단계

일반적인 상황에서 Transact-SQL 문이 종료된 후 튜플 이동 백그라운드 작업이 시작되면 백그라운드 작업은 보이지 않는 행 그룹 R1과 세그먼트 S1을 제거합니다. 새 Transact-SQL 문을 지금 시작하고 새 로컬 사전이 필요한 새 세그먼트 S3이 있는 행 그룹 R3을 만드는 경우 사전 D1의 내부 ID를 다시 사용할 수 없습니다. 이는 열 저장소의 메모리 내 상태가 사용되는 사전 ID를 추적하기 때문입니다. 따라서 세그먼트 S3은 새 사전 D2를 참조합니다.

참고 이 단계의 조건은 일반적인 조건입니다. 따라서 손상이 발생하지 않습니다.

4단계

튜플 이동 작업이 적용되고 3단계에서 설명된 대로 수행되기 전에 SQL Server에서 사전 D1의 메모리 내 상태가 손실되면 이 문서에서 설명하는 문제가 발생합니다.

노트

  • 이 이벤트는 다음과 같은 이유로 발생합니다.

    • SQL Server에서 메모리 과부하가 발생하고 사전 D1의 메모리 내 콘텐츠가 메모리에서 제거됩니다.
    • SQL Server의 instance가 다시 시작됩니다.
    • 클러스터형 columnstore 인덱스가 포함된 데이터베이스가 오프라인 상태가 되었다가 다시 온라인 상태가 됩니다.
  • 이러한 이벤트 중 하나가 발생하고 SQL Server가 메모리 내 구조를 다시 로드하면 사전 D1 및 해당 내부 ID가 존재했다는 레코드가 없습니다. 이는 Transact-SQL 문이 종료되거나 단축될 때 사전 D1이 시스템 테이블에 유지되지 않았기 때문입니다.

  • 이 시점에서 튜플 이동 백그라운드 작업이 시작되면 3단계에서 설명하는 조건이 적용되므로 오류가 발생하지 않습니다.

  • 이전 글머리 기호 항목에 따라 튜플 이동 백그라운드 작업이 시작되기 전에 새 행 그룹 R3이 만들어지면 SQL Server는 새 사전 D1에 동일한 내부 ID를 할당하고 행 그룹 R3의 세그먼트 S3에 대한 사전 D1을 참조합니다.

  • 이전 작업 이후에 튜플 이동 백그라운드 작업이 시작되면 새 사전 D1과 함께 보이지 않는 행 그룹 R1 및 세그먼트 S1을 삭제합니다. 이는 튜플 이동자가 S1이 참조하는 새 사전 D1과 원래 사전 D1이 동일하다고 고려하기 때문에 발생합니다.

    참고 이 조건이 발생하면 rowgroup R3의 내용을 쿼리할 수 없습니다.

해결 방법

이 문제는 SQL Server에 대한 다음 누적 업데이트에서 처음 해결되었습니다.

SQL Server 2014 SP1용 누적 업데이트 1
        
         SQL Server 2014용 누적 업데이트 8
이 문제에 대한 수정은 다음 GDR(일반 배포 릴리스) 업데이트에도 포함되어 있습니다.

SQL Server 2014 QFE용 보안 업데이트  
이 업데이트에는 누적 업데이트 8, 이 중요 수정 사항 및 필수 MS15-058 보안 업데이트가 포함되어 있습니다.

SQL Server 2014 GDR용 보안 업데이트  
이 업데이트에는 이 중요한 수정 사항과 MS15-058을 통한 누적 보안 수정 사항이 포함되어 있습니다.

SQL Server 2014 서비스 팩 1 GDR용 비보안 업데이트  
이 업데이트에는 이 중요한 픽스만 포함되어 있습니다.

SQL Server의 누적 업데이트 정보

SQL Server에 대한 각각의 새로운 누적 업데이트에는 이전 누적 업데이트에 포함된 모든 핫픽스와 모든 보안 수정 사항이 포함되어 있습니다. SQL Server에 대한 최신 누적 업데이트 보기:

      

추가 정보

오류 메시지 현재 영향을 받는 데이터베이스에서 이 수정 사항을 적용한 후 DBCC CHECKDB를 실행하면 다음과 같은 오류 메시지가 표시됩니다.

참고

메시지 5289, 수준 16, 상태 1, 줄 1
't' 테이블의 클러스터형 columnstore 인덱스 'cci'에 사전의 데이터 값과 일치하지 않는 데이터 값이 하나 이상 있습니다. 백업에서 데이터를 복원합니다.

현재 영향을 받는 데이터베이스에서 이 수정을 적용한 후 영향을 받는 테이블을 검색하는 쿼리를 실행하면 다음 오류 메시지가 표시됩니다.

참고

메시지 5288, 수준 16, 상태 1, 줄 1
columnstore 인덱스에 사전의 데이터 값과 일치하지 않는 데이터 값이 하나 이상 있습니다. 자세한 내용은 DBCC CHECKDB를 실행하세요.

이러한 오류가 발생하면 영향을 받지 않는 열/행 그룹의 데이터를 대량으로 내보낸 다음 클러스터형 columnstore 인덱스를 삭제하거나 만든 후 데이터를 다시 로드하여 손상되지 않은 데이터를 저장할 수 있습니다. 5288 오류를 억제하고 손상된 행 그룹을 건너뛰는 이전 동작으로 되돌리기려면 추적 플래그 10207을 사용하도록 설정해야 합니다.

참고: 세그먼트 S3이 있는 이 행 그룹 R3에 대해 오류 메시지 5288 및 5289가 생성됩니다. 추적 플래그 10207은 누락된 사전 D1의 영향을 받지 않는 행 그룹 R3의 세그먼트를 추출하는 데 사용됩니다.

영향을 받는 데이터베이스 쿼리 columnstore 인덱스가 포함된 데이터베이스가 이미 이 문제의 영향을 받고 있는지 확인하려면 다음 쿼리를 실행합니다.

select  
       object_name(i.object_id) as table_name, 
       i.name as index_name, 
       p.partition_number, 
       count(distinct s.segment_id) as damaged_rowgroups 
from 
       sys.indexes i 
       join sys.partitions p on p.object_id = i.object_id and p.index_id = i.index_id 
       join sys.column_store_row_groups g on g.object_id = i.object_id and g.index_id = i.index_id and g.partition_number = p.partition_number 
       join sys.column_store_segments s on s.partition_id = p.partition_id and s.segment_id = g.row_group_id 
where  
       i.type in (5, 6) 
       and s.secondary_dictionary_id <> -1  
       and g.state_description = 'COMPRESSED' 
       and s.secondary_dictionary_id not in 
       ( 
              select dictionary_id from sys.column_store_dictionaries d 
              where d.hobt_id = p.hobt_id and d.column_id = s.column_id 
       ) 
group by  
       object_name(i.object_id), 
       i.name, 
       p.partition_number 

노트

  • SQL Server를 실행하는 서버의 열 저장소 인덱스가 포함된 모든 데이터베이스에 대해 이 쿼리를 실행해야 합니다. 빈 결과 집합은 데이터베이스가 영향을 받지 않음을 나타냅니다.

  • 새 rowgroup을 만들거나 기존 rowgroup의 상태를 변경하는 활동이 없는 기간 동안 이 쿼리를 실행합니다. 예를 들어 인덱스 빌드, 인덱스 재구성, 대량 삽입, 튜플 이동기 델타 저장소 압축 등의 활동이 행 그룹의 상태를 수정할 수 있습니다.

    쿼리를 실행하기 전에 추적 플래그 634를 사용하여 백그라운드 튜플 이동 작업을 사용하지 않도록 설정할 수 있습니다. 이 명령을 사용하여 백그라운드 작업을 사용하지 않도록 설정합니다. DBCC TRACEON ( 634 , -1 ). 쿼리 실행이 완료되면 DBCC TRACEOFF ( 634 , -1 ) 명령을 사용하여 백그라운드 작업을 다시 사용하도록 설정해야 합니다.

    또한 이 쿼리가 실행되는 동안 columnstore 인덱스를 사용하는 테이블에 데이터를 삽입하는 BULK INSERT/BCP/SELECT-INTO 명령이 없는지 확인합니다.

    쿼리가 가양성을 반환하지 않도록 하려면 다음 단계를 사용하는 것이 좋습니다.

상태

Microsoft에서 이는 "적용 대상" 섹션에 나열된 Microsoft 제품에서의 문제임을 확인했습니다.