Có cách nào để giải quyết khi bạn muốn đặt OR bên trong chỉ mục được lọc không?


8

Có cách nào để giải quyết khi bạn muốn đặt OR bên trong chỉ mục được lọc không?

create index FIDX_tblbOrders_sdtmOrdCreated_INCL 
on dbo.tblBOrder(sdtmOrdCreated)
INCLUDE (sintMarketID,
         strCurrencyCode,
         sintOrderStatusID
         )
WHERE ((sintMarketId=1)
AND ( (sintOrderStatusId < 9) OR (sintOrderStatusId > 14)))

Tôi đang cố gắng tạo chỉ mục ở trên, vì tôi KHÔNG quan tâm đến bất kỳ tình huống nào trong đó sintOrderStatusId IN (9-14)

Tất nhiên tôi có thể tạo chế độ xem hoặc chế độ xem được lập chỉ mục, nhưng tôi đã cố tránh điều đó.

chỉ cần thêm thông tin: sintOrderStatusId là một phần nhỏ KHÔNG PHẢI và các giá trị có thể nằm trong khoảng từ 1 đến 30. 9 đến 14 là phải tránh, do đó chỉ số được lọc.

Câu trả lời:


12

Thật không may, dường như không có cách nào để tạo bộ lọc âm cho một chỉ mục, mà không dùng đến việc tạo ra một khung nhìn cụ thể hóa. Nếu nó đã có thể tạo ra một bộ lọc tiêu cực như một trong những bạn muốn, nó sẽ là khá khó khăn đối với các truy vấn tối ưu hóa để "nhặt" các chỉ số để sử dụng, tăng đáng kể thời gian cần thiết để tìm ra một kế hoạch tốt.

Tùy thuộc vào các mẫu truy vấn cho bảng này, bạn có thể chỉ cần tạo hai chỉ mục; một cho ít hơn 9 và một cho lớn hơn 14. Một trong hai chỉ mục này có thể được chọn bởi trình tối ưu hóa truy vấn cho WHEREcác mệnh đề đơn giản nhưWHERE StatusID = 6

CREATE TABLE dbo.TestNegativeFilter
(
    TestNegativeFilter INT NOT NULL
        CONSTRAINT PK_TestNegativeFilter
        PRIMARY KEY CLUSTERED
        IDENTITY(1,1)
    , StatusID INT NOT NULL
);
GO

CREATE INDEX IX_TestNagativeFilter_LessThan9
ON dbo.TestNegativeFilter(StatusID)
WHERE (StatusID < 9);

CREATE INDEX IX_TestNagativeFilter_GreaterThan14
ON dbo.TestNegativeFilter(StatusID)
WHERE (StatusID > 14);

Một cách khác để thực hiện điều này có thể là:

CREATE INDEX IX_TestNegativeFilter_9_to_14
ON dbo.TestNegativeFilter(StatusID)
WHERE (StatusID IN (9, 10, 11, 12, 13, 14));

SELECT *
FROM dbo.TestNegativeFilter tnf
EXCEPT
SELECT *
FROM dbo.TestNegativeFilter tnf
WHERE tnf.StatusID IN (9, 10, 11, 12, 13, 14);

Điều này sử dụng chỉ mục được lọc từ 9 đến 14 để loại trừ các hàng.

Trong thử nghiệm của tôi, một chỉ số bao phủ đơn giản trả về các hàng nhanh nhất:

CREATE NONCLUSTERED INDEX IX_TestNegativeFilter_StatusID
ON dbo.TestNegativeFilter(StatusID)
INCLUDE (TestNegativeFilter);

SELECT *
FROM dbo.TestNegativeFilter tnf
WHERE tnf.StatusID NOT IN (9, 10, 11, 12, 13, 14);

Ngoài ra, sử dụng một biến thể của cách tiếp cận được sử dụng trong câu trả lời của riêng bạn :

CREATE INDEX [IX dbo.TestNegativeFilter StatusID not 9-14]
ON dbo.TestNegativeFilter (StatusID)
WHERE StatusID <> 9
AND StatusID <> 10
AND StatusID <> 11
AND StatusID <> 12
AND StatusID <> 13
AND StatusID <> 14;

Mặc dù bộ lọc được viết dưới dạng liên từ, nó hỗ trợ các truy vấn được viết theo bất kỳ cách nào sau đây (cách đầu tiên hiệu quả hơn một chút):

  • StatusID NOT IN (9, 10, 11, 12, 13, 14)
  • StatusID < 9 OR StatusID > 14
  • StatusID NOT BETWEEN 9 AND 14

1

không tuyệt vời, nhưng dường như đang hoạt động:

create index FIDX_tblbOrders_sdtmOrdCreated_INCL 
on dbo.tblBOrder(sdtmOrdCreated)
INCLUDE (sintMarketID,
         strCurrencyCode,
         sintOrderStatusID
         )
WHERE ((sintMarketId=1)
AND ( sintOrderStatusId IN (0,1,2,3,4,5,6,7,8,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30)))

Khi tôi cố gắng làm theo cách tốt hơn, nó không thích:

nhập mô tả hình ảnh ở đây


1
Theo tài liệu MSND: "Các chỉ mục được lọc được xác định trên một bảng và chỉ hỗ trợ các toán tử so sánh đơn giản. Nếu bạn cần một biểu thức lọc tham chiếu nhiều bảng hoặc có logic phức tạp, bạn nên tạo chế độ xem." msdn.microsoft.com/en-us/l Library / cc280372.aspx
Paweł Tajs
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.