Điều kiện lọc không được áp dụng chính xác cho chỉ mục Clustered Columnstore


10

Sử dụng ví dụ dưới đây, các vị từ giống nhau, tuy nhiên câu lệnh trên cùng (chính xác) trả về 0 hàng, câu lệnh dưới cùng trả về 1 - mặc dù các vị từ KHÔNG khớp:

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

Tại sao điều này có thể xảy ra?

Thêm thông tin:

  • Chỉ mục không được nhóm trong câu lệnh hàng đầu KHÔNG được lọc
  • CheckDB trả về 0 vấn đề
  • Phiên bản máy chủ: Microsoft SQL Azure (RTM) - 12.0.2000.8 Dec 19 2018 08:43:17 Copyright (C) 2018 Microsoft Corporation

Dán liên kết Kế hoạch:

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

Thêm thông tin:

Đã chạy dbcc checktable ([transaction]) with all_errormsgs, extended_logical_checks, data_puritymà chỉ ra không có vấn đề.

Tôi có thể tái tạo một cách đáng tin cậy vấn đề đối với bảng này khi khôi phục bản sao lưu của cơ sở dữ liệu này.


Bình luận không dành cho thảo luận mở rộng; cuộc trò chuyện này đã được chuyển sang trò chuyện .
Jack nói hãy thử topanswers.xyz

Câu trả lời:


7

Lỗi này không yêu cầu thả hoặc đổi tên cột.

Bạn cũng sẽ thấy hành vi tương tự statusId = 100chưa từng có trong bất kỳ phiên bản nào của cột.

Yêu cầu

  • Một cửa hàng cột
  • Chỉ số cây b không bao gồm
  • Một kế hoạch thực hiện tra cứu trên các cửa hàng cột với
    • Hàng mục tiêu trong cửa hàng delta
    • Một vị từ không SARG được đẩy
    • So sánh với NULL bằng kiểm tra đẳng thức

Thí dụ

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;

Bất kỳ điều nào sau đây sẽ tránh được lỗi:

  • Di chuyển các hàng ra khỏi cửa hàng delta bằng bất kỳ phương pháp nào, bao gồm sắp xếp lại với tùy chọn nhóm hàng nén được chỉ định
  • Viết vị ngữ để từ chối rõ ràng = NULL
  • Kích hoạt cờ theo dõi không có giấy tờ 9130 để tránh đẩy vị ngữ vào tra cứu

db <> fiddle demo.


Lỗi này đã được sửa trong CU15 cho SQL Server 2017 (và CU7 cho SQL Server 2016 SP2):

CỐ ĐỊNH: Truy vấn đối với bảng có cả chỉ mục kho lưu trữ phân cụm và chỉ mục kho hàng không được phân loại có thể trả về kết quả không chính xác trong SQL Server 2016 và 2017


8

Đây là một lỗi với SQL Server. Nếu một cột bị xóa khỏi một bảng có chỉ mục cửa hàng cột được phân cụm, và sau đó một cột mới được thêm cùng tên, thì nó dường như đang sử dụng cột cũ, bị xóa cho vị ngữ. Đây là MVCE:

Kịch bản này bắt đầu với 10000hàng với statusIdcủa 1statusId2của 5- sau đó giảm các statusIDcột và đặt lại tên statusId2để statusId. Vì vậy, ở cuối tất cả các hàng nên có statusId5.

Nhưng truy vấn sau đây đánh vào chỉ mục không được nhóm ...

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

... và trả về 2các hàng (với lựa chọn statusIdkhác với ngụ ý của WHEREmệnh đề) ...

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

... trong khi cái này truy cập vào kho cột và trả về đúng 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;

Tôi cũng đã nêu ra một vấn đề trên cổng thông tin phản hồi Azure :

Và đối với bất kỳ ai khác gặp phải điều này, việc xây dựng lại Indexed Clusterstore Index sẽ khắc phục vấn đề:

alter index cci_example on example rebuild

Xây dựng lại CCI chỉ sửa chữa bất kỳ dữ liệu hiện có. Nếu hồ sơ mới được thêm vào, vấn đề phát sinh lại trên các hồ sơ này; Vì vậy, hiện tại sửa chữa duy nhất được biết cho bảng là để tạo lại nó hoàn toàn.


1
Không chỉ là vấn đề mà nó đang sử dụng cái cũ cho vị ngữ. Điều kỳ lạ khác là nó hoàn toàn phá vỡ vị còn sót lại trên các cột khác nhau and id2 = @id2nên đảm bảo không hàng anyway như @id2nullnhưng bạn vẫn nhận được 2
Martin Smith

RE: Chỉnh sửa 2 của bạn không REORGANIZE WITH (COMPRESS_ALL_ROW_GROUPS = ON);thực hiện công việc? Điều đó sẽ xóa deltastore - vấn đề vẫn còn xảy ra đối với các hàng mới được thêm vào sau đó?
Martin Smith

Không, dường như là kết quả chính xác đáng buồn?
Uberzen1

-4

Dựa trên các kế hoạch, có vẻ như chỉ mục Cột được tạo với TẮT ANSI_NULLS. Các bảng và chỉ mục giữ lại cài đặt như khi chỉ mục được tạo. Bạn có thể kiểm tra bằng cách tạo một chỉ mục Cột lưu trữ trùng lặp trong khi đảm bảo rằng ANSI_NULLS được BẬT, sau đó bỏ bản gốc hoặc vô hiệu hóa nó.

Nhưng, trừ khi bạn đã phát hiện ra lỗi SQL Server, đây là cách duy nhất mà kết quả có thể xảy ra.


2
Bạn có chắc chắn rằng 1) các chỉ mục không được lọc có thể duy trì các cài đặt ANSI_NULLS tách biệt với bảng cơ sở và 2) rằng cài đặt ANSI_NULLS phiên có thể thực sự gây ra sự khác biệt khi bảng được tạo với ANSI_NULLS OFF không?
Forrest

Tôi đã nghĩ điều này, nhưng khi tôi viết ra định nghĩa của CCI thì nó không có tùy chọn nào được đặt và nếu tôi tạo nó với SET ANSI_NULLS ON trước khi định nghĩa chỉ mục thì kết quả có giống nhau không?
Uberzen1
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.