클러스터 된 Columnstore 인덱스에 필터 조건이 올바르게 적용되지 않음


10

아래 예제를 사용하면 술어는 동일하지만 최상위 명령문 (올바로)은 0 개의 행을 리턴하고, 하단 명령문은 1을 리턴합니다.

declare @barcode nchar(22)=N'RECB012ZUKI449M1VBJZ'  
declare @tableId int = null
declare @total decimal(10, 2) = 5.17

SELECT 1
FROM
    [dbo].[transaction] WITH (INDEX([IX_Transaction_TransactionID_PaymentStatus_DeviceID_DateTime_All]))
WHERE
    Barcode = @barcode
    AND StatusID = 1
    AND TableID = @tableID
    AND @total <= Total

SELECT 1
FROM
    [dbo].[transaction] 
WHERE
    Barcode = @barcode
    AND StatusID = 1
    AND TableID = @tableID
    AND @total <= Total

왜 이런 일이 일어날 수 있습니까?

추가 정보 :

  • 상단 문장의 비 클러스터형 인덱스는 필터링되지 않습니다
  • CheckDB는 0 문제를 반환
  • 서버 버전 : Microsoft SQL Azure (RTM) - 12.0.2000.8 Dec 19 2018 08:43:17 Copyright (C) 2018 Microsoft Corporation

계획 링크를 붙여 넣습니다.

https://www.brentozar.com/pastetheplan/?id=S1w_rU68E

추가 정보 :

dbcc checktable ([transaction]) with all_errormsgs, extended_logical_checks, data_purity문제가 없음 을 나타내는 실행 했습니다.

이 데이터베이스의 백업을 복원 할 때이 테이블에 대한 문제를 안정적으로 재현 할 수 있습니다.


의견은 긴 토론을위한 것이 아닙니다. 이 대화는 채팅 으로 이동 되었습니다 .
잭 topanswers.xyz 시도라고

답변:


7

이 버그는 열을 삭제하거나 이름을 바꿀 필요가 없습니다.

또한 statusId = 100열의 어떤 버전에도 존재하지 않는 동일한 동작을 볼 수 있습니다 .

요구 사항

  • 클러스터형 열 저장소
  • 비 클러스터형 b- 트리 인덱스
  • columnstore에서 조회를 수행하는 계획
    • 델타 저장소 의 대상 행
    • 푸시 된 비 SARG 술어
    • 동등성 테스트를 사용하여 NULL과 비교

DROP TABLE IF EXISTS dbo.Example;
GO
CREATE TABLE dbo.Example
(
    c1 integer NOT NULL,
    c2 integer NULL,

    INDEX CCS CLUSTERED COLUMNSTORE,
    INDEX IX NONCLUSTERED (c1)
);
GO
INSERT dbo.Example
    (c1, c2)
VALUES
    (1, NULL);
GO
DECLARE @c2 integer = NULL;

-- Returns one row but should not
SELECT
    E.* 
FROM dbo.Example AS E 
    WITH (INDEX(IX))
WHERE
    E.c2 = @c2;

다음 중 하나라도 버그를 피할 수 있습니다.

  • 지정된 행 그룹 압축 옵션으로 재구성을 포함하여 모든 방법을 사용하여 델타 저장소 밖으로 행 이동
  • 명시 적으로 거부 할 술어 작성 = NULL
  • 술어를 찾아 보지 않도록 문서화되지 않은 추적 플래그 9130 사용

db <> 바이올린 데모.


이 버그는 SQL Server 2017 CU15 및 SQL Server 2016 SP2 CU7에서 수정 되었습니다.

FIX : 클러스터 된 columnstore 인덱스와 클러스터되지 않은 rowstore 인덱스가 모두있는 테이블에 대한 쿼리가 SQL Server 2016 및 2017에서 잘못된 결과를 반환 할 수 있음


8

이것은 SQL Server의 버그입니다. 클러스터 된 columnstore 인덱스가있는 테이블에서 열을 삭제 한 다음 동일한 이름으로 새 열을 추가하면 술어에 대해 삭제 된 이전 열을 사용하는 것으로 나타납니다. MVCE는 다음과 같습니다.

이 스크립트와 함께 시작합니다 10000과 행 statusId1statusId25- 다음 떨어 statusID컬럼 및 이름 변경 statusId2에를 statusId. 결국 모든 행은 statusId5의 값을 가져야합니다 .

그러나 다음 쿼리는 클러스터되지 않은 인덱스에 도달합니다 ...

select *
from example
where statusId = 1
    and total <= @filter
    and barcode = @barcode
    and id2 = @id2

... 2(행이 statusId암시 한 것과 다른 선택)을 반환합니다 WHERE...

+-------+---------+------+-------+----------+
|  id   | barcode | id2  | total | statusId |
+-------+---------+------+-------+----------+
|     5 |    5    | NULL |  5.00 |        5 |
| 10005 |    5    | NULL |  5.00 |        5 |
+-------+---------+------+-------+----------+

... 이것은 columnstore에 액세스하고 올바르게 반환합니다. 0

select count(*) 
from example 
where statusId = 1

MVCE

/*Create table with clustered columnstore and non clustered rowstore*/
CREATE TABLE example
(
id        INT IDENTITY(1, 1),
barcode   CHAR(22),
id2       INT,
total     DECIMAL(10,2),
statusId  TINYINT,
statusId2 TINYINT,
INDEX cci_example CLUSTERED COLUMNSTORE,
INDEX ix_example (barcode, total)
);

/* Insert 10000 rows all with (statusId,statusId2) = (1,5) */
INSERT example
       (barcode,
        id2,
        total,
        statusId,
        statusId2)
SELECT TOP (10000) barcode = row_number() OVER (ORDER BY @@spid),
                   id2 = NULL,
                   total = row_number() OVER (ORDER BY @@spid),
                   statusId = 1,
                   statusId2 = 5
FROM   sys.all_columns c1, sys.all_columns c2;

ALTER TABLE example
  DROP COLUMN statusid
/* Now have 10000 rows with statusId2 = 5 */


EXEC sys.sp_rename
  @objname = N'dbo.example.statusId2',
  @newname = 'statusId',
  @objtype = 'COLUMN';
/* Now have 10000 rows with StatusID = 5 */

INSERT example
       (barcode,
        id2,
        total,
        statusId)
SELECT TOP (10000) barcode = row_number() OVER (ORDER BY @@spid),
                   id2 = NULL,
                   total = row_number() OVER (ORDER BY @@spid),
                   statusId = 5
FROM   sys.all_columns c1, sys.all_columns c2;
/* Now have 20000 rows with StatusID = 5 */


DECLARE @filter  DECIMAL = 5,
        @barcode CHAR(22) = '5',
        @id2     INT = NULL; 

/*This returns 2 rows from the NCI*/
SELECT *
FROM   example WITH (INDEX = ix_example)
WHERE  statusId = 1
       AND total <= @filter
       AND barcode = @barcode
       AND id2 = @id2;

/*This counts 0 rows from the Columnstore*/
SELECT COUNT(*)
FROM   example
WHERE  statusId = 1;

Azure 피드백 포털 에서도 문제가 발생했습니다 .

그리고이 문제가 발생하는 다른 사람들을 위해 Clustered Columnstore Index를 다시 작성하면 문제가 해결됩니다.

alter index cci_example on example rebuild

CCI를 재 구축하면 기존 데이터 만 수정됩니다. 새 레코드가 추가되면이 레코드에서 문제가 다시 발생합니다. 따라서 현재 테이블에 대해 알려진 유일한 수정은 테이블을 완전히 다시 작성하는 것입니다.


1
술어에 대해 이전 문제를 사용하고있는 문제 만이 아닙니다. 다른 이상한 점은 완전히 다른 컬럼에 잔류 조건을 나누기 때문이다 and id2 = @id2어쨌든 제로 행을 보장해야 @id2입니다 null하지만 당신은 여전히이 얻을
마틴 스미스

RE : 편집 2가 REORGANIZE WITH (COMPRESS_ALL_ROW_GROUPS = ON);작업을 수행합니까? deltastore가 지워집니다. 그 뒤에 추가 된 새 행에 문제가 계속 발생합니까?
Martin Smith

아니, 슬프게도 정확히 같은 결과 인 것 같습니까?
Uberzen1

-4

계획에 따라 Columnstore 인덱스가 SET ANSI_NULLS OFF로 생성 된 것으로 보입니다. 테이블과 인덱스는 인덱스를 만들 때와 같이 설정을 유지합니다. ANSI_NULLS가 켜져 있는지 확인한 후 원본을 삭제하거나 비활성화하여 중복 Columnstore 색인을 작성하여 확인할 수 있습니다.

그러나 SQL Server 버그를 발견하지 않은 경우 결과가 발생할 수있는 유일한 방법입니다.


2
1) 필터링되지 않은 인덱스가 기본 테이블과 별도로 ANSI_NULLS 설정을 유지할 수 있고 2) ANSI_NULLS OFF로 테이블을 작성할 때 세션 ANSI_NULLS 설정이 실제로 불일치를 유발할 수 있습니까?
포레스트 포레스트

나는 이것을 생각했지만 CCI의 정의를 스크립트 할 때 설정된 옵션이 없으며 인덱스 정의 전에 SET ANSI_NULLS ON으로 작성하면 결과가 동일합니까?
Uberzen1
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.