Chỉ mục cột được tính toán không được sử dụng


14

Tôi muốn có một tra cứu nhanh dựa trên nếu hai cột bằng nhau. Tôi đã cố gắng sử dụng một cột được tính toán với một chỉ mục, nhưng SQL Server dường như không sử dụng nó. Nếu tôi chỉ sử dụng một cột bit dân cư tĩnh với một chỉ mục, tôi sẽ tìm kiếm chỉ mục mong đợi.

Có vẻ như có một số câu hỏi khác như thế này, nhưng không có câu hỏi nào tập trung vào lý do tại sao một chỉ mục sẽ không được sử dụng.

Bảng kiểm tra:

CREATE TABLE dbo.Diffs
    (
    Id int NOT NULL IDENTITY (1, 1),
    DataA int NULL,
    DataB int NULL,
    DiffPersisted  AS isnull(convert(bit, case when [DataA] is null and [DataB] is not null then 1 when [DataA] <> [DataB] then 1 else 0 end), 0) PERSISTED ,
    DiffComp  AS isnull(convert(bit, case when [DataA] is null and [DataB] is not null then 1 when [DataA] <> [DataB] then 1 else 0 end), 0),
    DiffStatic bit not null,
    Primary Key (Id)
    )

create index ix_DiffPersisted on Diffs (DiffPersisted)
create index ix_DiffComp on Diffs (DiffComp)
create index ix_DiffStatic on Diffs (DiffStatic)

Và truy vấn:

select Id from Diffs where DiffPersisted = 1
select Id from Diffs where DiffComp = 1
select Id from Diffs where DiffStatic = 1

Và kế hoạch thực hiện kết quả: Kế hoạch thực hiện

Câu trả lời:


10

Hãy thử với COALESCEthay vì ISNULL. Với ISNULL, SQL Server dường như không có khả năng đẩy một vị từ so với chỉ số hẹp hơn và do đó phải quét cụm để tìm thông tin.

CREATE TABLE dbo.Diffs
    (
    Id int NOT NULL IDENTITY (1, 1),
    DataA int NULL,
    DataB int NULL,
    DiffPersisted  AS COALESCE(convert(bit, case when [DataA] is null 
      and [DataB] is not null then 1 when [DataA] <> [DataB] 
      then 1 else 0 end), 0) PERSISTED ,
    DiffComp  AS COALESCE(convert(bit, case when [DataA] is null 
      and [DataB] is not null then 1 when [DataA] <> [DataB] 
      then 1 else 0 end), 0),
    DiffStatic bit not null,
    Primary Key (Id)
    );

Điều đó nói rằng, nếu bạn gắn bó với một cột tĩnh, một chỉ mục được lọc có thể có ý nghĩa hơn và sẽ có chi phí I / O thấp hơn (tất cả phụ thuộc vào số lượng hàng thường khớp với vị từ bộ lọc), vd:

CREATE INDEX ix_DiffStaticFiltered 
  ON dbo.Diffs(DiffStatic)
  WHERE DiffStatic = 1;

Rất thú vị, sẽ không nghĩ về điều này. Có vẻ như bạn chỉ có thể thoát khỏi COALESCEthời điểm này; Tôi tin rằng CASEcâu lệnh đã được đảm bảo trả về 0hoặc 1, nhưng ISNULLchỉ có mặt để SQL Server mang lại giá trị không thể rỗng BITcho cột được tính toán. Tuy nhiên, COALESCEvẫn sẽ mang lại một cột nullable. Vì vậy, một tác động của sự thay đổi này, có hoặc không có COALESCE, là cột được tính bây giờ là null nhưng tìm kiếm chỉ mục có thể được sử dụng.
Geoff Patterson

@Geoff Vâng, đó là sự thật. Nhưng trong trường hợp này vì chúng ta biết theo định nghĩa cột được tính toán, NULL thực sự không phải là đầu ra khả thi, điều này chỉ thực sự quan trọng nếu chúng ta sử dụng bảng này làm nguồn của CHỌN VÀO.
Aaron Bertrand

Đây là một số thông tin tuyệt vời - cảm ơn bạn! Mục tiêu cuối cùng của tôi là các cột DataA và DataB được sử dụng làm uuids "bẩn" để cho phép cập nhật không đồng bộ các cột không chuẩn hóa trên bản ghi, do đó không nên có quá nhiều cờ Diff là 1. Nếu tôi sử dụng tĩnh Sau đó, tôi đã nghĩ đến việc thêm một trình kích hoạt để theo dõi hai uuids và cập nhật trường.
David Faivre

Ngoài ra, như @GeoffPatterson đã chỉ ra, tôi không thể sử dụng COALESCE? Tại sao tôi sẽ giữ nó?
David Faivre

@David Có lẽ bạn có thể thả COALESCE. Tôi đã cố gắng duy trì giao diện và mục đích của mã ban đầu của bạn và đã không kiểm tra mà không có nó, vì vậy việc kiểm tra sẽ thuộc về bạn. (Tôi cũng không thể giải thích lý do tại sao bạn lại ISNULLở đó ngay từ đầu.)
Aaron Bertrand

5

Đây là một giới hạn cụ thể của logic đối sánh cột được tính toán của SQL Server, khi ISNULLsử dụng một lớp ngoài cùng và kiểu dữ liệu của cột là bit.

Báo cáo lỗi

Để tránh sự cố, bất kỳ cách giải quyết nào sau đây có thể được sử dụng:

  1. Không sử dụng ngoài cùng ISNULL(cách duy nhất để tạo cột được tính toán NOT NULL).
  2. Không sử dụng bitkiểu dữ liệu làm kiểu cuối cùng của cột được tính toán.
  3. Tạo cột được tính toán PERSISTEDbật cờ theo dõi 174 .

Chi tiết

Trọng tâm của vấn đề là không có cờ theo dõi 174, tất cả các tham chiếu cột được tính toán trong một truy vấn (thậm chí còn tồn tại) luôn được mở rộng thành định nghĩa cơ bản từ rất sớm trong quá trình biên dịch truy vấn.

Ý tưởng mở rộng là nó có thể cho phép đơn giản hóa và viết lại chỉ có thể hoạt động trên định nghĩa, không phải trên tên cột mà thôi. Ví dụ: có thể có các vị từ trong tham chiếu truy vấn mà cột được tính toán có thể làm cho một phần của phép tính dự phòng hoặc bị ràng buộc nhiều hơn.

Khi các đơn giản hóa và viết lại sớm được xem xét, quá trình biên dịch truy vấn sẽ khớp các biểu thức trong truy vấn với các cột được tính toán (tất cả các cột được tính toán, không chỉ các cột được tìm thấy trong văn bản truy vấn).

Các biểu thức cột được tính toán không thay đổi khớp với cột được tính toán ban đầu mà không gặp vấn đề gì trong hầu hết các trường hợp. Dường như có một lỗi khi cụ thể để khớp với một biểu thức bitloại, với lớp ngoài cùng ISNULL. Kết hợp là không thành công trong trường hợp cụ thể này, ngay cả khi kiểm tra chi tiết nội bộ cho thấy rằng nó sẽ thành công.

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.