Không thể tạo Chỉ mục được Lọc trên Cột được Tính


17

Trong một câu hỏi trước đây của tôi, Có phải là một ý tưởng tốt để vô hiệu hóa leo thang khóa trong khi thêm các cột được tính toán mới vào một bảng không? , Tôi đang tạo một cột được tính toán:

ALTER TABLE dbo.tblBGiftVoucherItem
ADD isUsGift AS CAST
(
    ISNULL(
        CASE WHEN sintMarketID = 2 
            AND strType = 'CARD'
            AND strTier1 LIKE 'GG%' 
        THEN 1 
        ELSE 0 
        END
    , 0) 
    AS BIT
) PERSISTED;

Cột được tính là PERSISTEDvà theo computing_column_def định (Transact-SQL) :

NGHIÊM TÚC

Chỉ định rằng Công cụ cơ sở dữ liệu sẽ lưu trữ vật lý các giá trị được tính toán trong bảng và cập nhật các giá trị khi bất kỳ cột nào khác mà cột được tính phụ thuộc được cập nhật. Đánh dấu một cột được tính là PERSISTED cho phép tạo một chỉ mục trên một cột được tính có tính xác định, nhưng không chính xác. Để biết thêm thông tin, hãy xem Chỉ mục trên Cột được tính toán. Bất kỳ cột được tính toán nào được sử dụng làm cột phân vùng của bảng được phân đoạn phải được đánh dấu rõ ràng PERSISTED. computing_column_expression phải có tính xác định khi PERSISTED được chỉ định.

Nhưng khi tôi cố gắng tạo một chỉ mục trên cột của mình, tôi gặp phải lỗi sau:

CREATE INDEX FIX_tblBGiftVoucherItem_incl
ON dbo.tblBGiftVoucherItem (strItemNo) 
INCLUDE (strTier3)
WHERE isUsGift = 1;

Chỉ mục được lọc 'FIX_tblBGiftVoucherItem_incl' không thể được tạo trên bảng 'dbo.tblBGiftVoucherItem' vì cột 'isUsGift' trong biểu thức lọc là cột được tính toán. Viết lại biểu thức lọc để nó không bao gồm cột này.

Làm cách nào để tạo chỉ mục được lọc trên cột được tính?

hoặc là

Có một giải pháp thay thế?


3
Bạn có thể tạo một chỉ mục được lọc trên WHERE (sintMarketID = 2 AND strType = 'CARD' AND strTier1 LIKE 'GG%')mặc dù.
ypercubeᵀᴹ

Câu trả lời:


20

Thật không may, kể từ SQL Server 2014, không có khả năng tạo Filtered IndexBộ lọc trong Cột được tính toán (bất kể có tồn tại hay không).

Đã có một Mục kết nối mở từ năm 2009, vì vậy hãy tiếp tục và bỏ phiếu cho nó. Có thể Microsoft sẽ sửa lỗi này một ngày.

Aaron Bertrand có một bài viết đề cập đến một số vấn đề khác với Chỉ mục được lọc .


21

Mặc dù bạn không thể tạo một chỉ mục được lọc trên một cột bền vững, có một cách giải quyết khá đơn giản mà bạn có thể sử dụng.

Để thử nghiệm, tôi đã tạo một bảng đơn giản với một IDENTITYcột và một cột được tính toán bền vững dựa trên cột nhận dạng:

USE tempdb;

CREATE TABLE dbo.PersistedViewTest
(
    PersistedViewTest_ID INT NOT NULL
        CONSTRAINT PK_PersistedViewTest
        PRIMARY KEY CLUSTERED
        IDENTITY(1,1)
    , SomeData VARCHAR(2000) NOT NULL
    , TestComputedColumn AS (PersistedViewTest_ID - 1) PERSISTED
);
GO

Sau đó, tôi đã tạo chế độ xem ràng buộc lược đồ dựa trên bảng với bộ lọc trên cột được tính toán:

CREATE VIEW dbo.PersistedViewTest_View
WITH SCHEMABINDING
AS
SELECT PersistedViewTest_ID
    , SomeData 
    , TestComputedColumn
FROM dbo.PersistedViewTest
WHERE TestComputedColumn < CONVERT(INT, 27);

Tiếp theo, tôi đã tạo một chỉ mục được nhóm trên khung nhìn ràng buộc lược đồ, có tác dụng duy trì các giá trị được lưu trong khung nhìn, bao gồm giá trị của cột được tính toán:

CREATE UNIQUE CLUSTERED INDEX IX_PersistedViewTest
ON dbo.PersistedViewTest_View(PersistedViewTest_ID);
GO

Chèn một số dữ liệu thử nghiệm vào bảng:

INSERT INTO dbo.PersistedViewTest (SomeData)
SELECT o.name + o1.name + o2.name
FROM sys.objects o
    CROSS JOIN sys.objects o1
    CROSS JOIN sys.objects o2;

Tạo một mục thống kê và một chỉ mục trên khung nhìn:

CREATE STATISTICS ST_PersistedViewTest_View
ON dbo.PersistedViewTest_View(TestComputedColumn)
WITH FULLSCAN;

CREATE INDEX IX_PersistedViewTest_View_TestComputedColumn
ON dbo.PersistedViewTest_View(TestComputedColumn);

Việc thực hiện các SELECTcâu lệnh đối với bảng với cột được duy trì giờ đây có thể tự động sử dụng chế độ xem được duy trì, nếu trình tối ưu hóa truy vấn xác định điều đó có ý nghĩa để làm như vậy:

SELECT pv.PersistedViewTest_ID
    , pv.TestComputedColumn
FROM dbo.PersistedViewTest pv
WHERE pv.TestComputedColumn = CONVERT(INT, 26)

Kế hoạch thực hiện thực tế cho truy vấn trên cho thấy trình tối ưu hóa truy vấn đã chọn sử dụng chế độ xem được duy trì để trả về kết quả:

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

Bạn có thể đã nhận thấy sự chuyển đổi rõ ràng trong WHEREmệnh đề trên. Rõ ràng này CONVERT(INT, 26)cho phép trình tối ưu hóa truy vấn sử dụng đúng đối tượng thống kê để ước tính số lượng hàng sẽ được truy vấn trả về. Nếu chúng ta viết truy vấn WHERE pv.TestComputedColumn = 26, trình tối ưu hóa truy vấn có thể không ước tính đúng số lượng hàng vì 26 thực sự được coi là a TINY INT; điều này có thể khiến SQL Server không sử dụng chế độ xem liên tục. Chuyển đổi ngầm định có thể rất đau đớn và phải trả tiền để sử dụng nhất quán các loại dữ liệu chính xác để so sánh và tham gia.

Tất nhiên, tất cả các "gotchas" tiêu chuẩn do sử dụng liên kết lược đồ đều áp dụng cho kịch bản trên; điều này có thể ngăn việc sử dụng cách giải quyết này trong tất cả các tình huống. Chẳng hạn, sẽ không còn có thể sửa đổi bảng cơ sở mà không loại bỏ ràng buộc lược đồ khỏi khung nhìn. Để làm điều đó, bạn sẽ cần xóa chỉ mục được nhóm khỏi chế độ xem.

Nếu bạn không có SQL Server Enterprise Edition, trình tối ưu hóa truy vấn sẽ không tự động sử dụng chế độ xem được duy trì cho các truy vấn không tham chiếu trực tiếp chế độ xem bằng WITH (NOEXPAND)gợi ý. Để nhận ra lợi ích của việc sử dụng chế độ xem bền vững trong các phiên bản không dành cho Doanh nghiệp, bạn sẽ cần phải viết lại truy vấn ở trên thành một cái gì đó như:

SELECT pv.PersistedViewTest_ID
    , pv.TestComputedColumn
FROM dbo.PersistedViewTest_View pv WITH (NOEXPAND)
WHERE pv.TestComputedColumn = CONVERT(INT, 26)

Cảm ơn Ian Ringrose đã chỉ ra giới hạn Phiên bản doanh nghiệp ở trên và Paul White cho (NOEXPAND)gợi ý.

Câu trả lời này của Paul có một số chi tiết thú vị về trình tối ưu hóa truy vấn liên quan đến các quan điểm vẫn tồn tại.


Công việc xung quanh cho thấy rằng cả chỉ mục được nhóm và chỉ mục không bao gồm được tạo trên chế độ xem. Có phải chỉ số không bao gồm phải được sử dụng trên chỉ mục cụm vì một số lý do? Hoặc, chỉ số không bao gồm nhiều hiệu suất hơn? Nếu chỉ mục cụm được sử dụng trong truy vấn, số liệu thống kê sẽ hiển thị gì?
Bob Bryan

Câu hỏi thú vị, @BobBryan - chỉ mục được nhóm là bắt buộc để cho phép chế độ xem được duy trì, mặc dù thực tế nó không cần phải là một chỉ mục duy nhất. Tôi có thể đã tạo chỉ mục được nhóm của chế độ xem trên một số cột khác, chẳng hạn như TestComputedColumnthay thế. Tuy nhiên, vì chỉ mục được nhóm chứa tất cả dữ liệu cho bảng / khung nhìn, tôi quyết định sẽ tốt hơn nếu sử dụng số tăng đơn điệu làm khóa phân cụm. Lưu ý, tôi đã không thực sự kiểm tra giả định đó và thực tế nó có thể không chính xác đối với một số biến thể của repro.
Max Vernon

Lưu ý, chỉ mục không được phân cụm không phải là một chỉ mục bao trùm và vì vậy, bất kỳ truy vấn nào lọc, tham gia hoặc trả về các cột từ chế độ xem hoặc bảng bên dưới sẽ cần thực hiện thao tác tra cứu khóa đối với bảng cơ sở hoặc quan điểm. Có khả năng là đối với một kịch bản trong thế giới thực, phạm vi câu trả lời hạn chế của tôi có thể được giải thích với hiệu suất thậm chí tốt hơn trong tâm trí.
Max Vernon

4

Từ Create Indexwheremệnh đề của nó , điều này là không thể:

Ở ĐÂU

Tạo một chỉ mục được lọc bằng cách chỉ định các hàng sẽ bao gồm trong chỉ mục. Chỉ mục được lọc phải là chỉ mục không bao gồm trên bảng. Tạo số liệu thống kê được lọc cho các hàng dữ liệu trong chỉ mục được lọc.

Vị từ bộ lọc sử dụng logic so sánh đơn giản và không thể tham chiếu cột được tính toán, cột UDT, cột kiểu dữ liệu không gian hoặc cột kiểu dữ liệu phân cấp. Việc so sánh sử dụng chữ NULL không được phép với các toán tử so sánh. Thay vào đó, hãy sử dụng toán tử IS NULL và IS NOT NULL.

Nguồn: MSDN


3
  • Bạn cần một cột không được tính toán để đặt chỉ mục được lọc vào.
  • Bạn cần tính toán giá trị để đi trong cột đó.

Trước khi tính toán các cột, chúng tôi đã sử dụng các kích hoạt để tính giá trị cột bất cứ khi nào hàng được thay đổi hoặc chèn.

(Cũng có thể sử dụng kích hoạt để chèn / xóa PK của mục khỏi bảng thứ 2 được sử dụng trong các truy vấn.)


3

Đây là một nỗ lực cải thiện công việc của Max Vernon . Trong giải pháp của mình, ông đề nghị sử dụng 2 chỉ mục trên chế độ xem và đối tượng thống kê.

Chỉ mục thứ nhất được phân cụm, điều này thực sự cần thiết vì không giống như chỉ mục không được bao gồm trên bảng, sẽ xảy ra lỗi nếu tạo chỉ mục không được bao gồm trên chế độ xem mà không có chỉ mục được nhóm trước.

Chỉ mục thứ 2 là một chỉ mục không bao gồm, được sử dụng làm chỉ mục đằng sau truy vấn. Trong phần bình luận câu trả lời của anh ấy, tôi đã hỏi điều gì sẽ xảy ra nếu một chỉ mục được sử dụng thay vì một chỉ mục không bao gồm.

Các phân tích sau đây cố gắng trả lời câu hỏi này.

Tôi đang sử dụng cùng một mã chính xác của mình, ngoại trừ tôi không tạo chỉ mục không bao gồm trong chế độ xem.

Tôi cũng không tạo ra một đối tượng thống kê. Nếu bạn đang theo dõi và sử dụng SQL Server Management Studio (SSMS) để nhập mã bên dưới, bạn nên lưu ý rằng bạn có thể thấy một số dòng nguệch ngoạc màu đỏ - trông giống như lỗi. Đây không phải là lỗi, nhưng liên quan đến một vấn đề với intellisense.

Bạn có thể vô hiệu hóa intellisense hoặc chỉ cần bỏ qua các lỗi và chạy các lệnh. Họ nên hoàn thành mà không có lỗi.

-- Create the test table that uses a computed column.
USE tempdb;
CREATE TABLE dbo.PersistedViewTest
(
    PersistedViewTest_ID INT NOT NULL
    CONSTRAINT PK_PersistedViewTest
    PRIMARY KEY CLUSTERED
    IDENTITY(1,1)
    , SomeData VARCHAR(2000) NOT NULL
    , TestComputedColumn AS (PersistedViewTest_ID - 1) PERSISTED
);
GO

-- Insert some test data into the table.
INSERT INTO dbo.PersistedViewTest (SomeData)
SELECT o.name + o1.name + o2.name
FROM sys.objects o
    CROSS JOIN sys.objects o1
    CROSS JOIN sys.objects o2;
GO

Kế hoạch thực hiện sau (không có chế độ xem / chỉ mục) được tạo sau khi truy vấn sau được chạy với bảng:

SELECT pv.PersistedViewTest_ID, pv.TestComputedColumn
FROM dbo.PersistedViewTest pv
WHERE pv.TestComputedColumn = CONVERT(INT, 26)
GO

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

Điều này đưa ra một đường cơ sở để so sánh với. Lưu ý rằng sau khi truy vấn hoàn thành, một đối tượng thống kê đã được tạo (_WA_Sys_00000003_1FCDBCEB). Đối tượng thống kê PK_PersistedViewTest đã được tạo khi chỉ mục bảng phân cụm được tạo.

Tiếp theo, chế độ xem được lọc và chỉ mục được nhóm trên chế độ xem đó được tạo:

-- Create filtered view on the computed column.
CREATE VIEW dbo.PersistedViewTest_View
WITH SCHEMABINDING
AS
SELECT PersistedViewTest_ID, SomeData, TestComputedColumn
FROM dbo.PersistedViewTest
WHERE TestComputedColumn < CONVERT(INT, 27);
GO

-- Create unique clustered index to persist the values, including the computed column.
CREATE UNIQUE CLUSTERED INDEX IX_PersistedViewTest
ON dbo.PersistedViewTest_View(PersistedViewTest_ID);
GO

Bây giờ, hãy thử chạy lại truy vấn, nhưng lần này ngược lại với chế độ xem:

SELECT pv.PersistedViewTest_ID, pv.TestComputedColumn
FROM dbo.PersistedViewTest_View pv
WHERE pv.TestComputedColumn = CONVERT(INT, 26)
GO

Kế hoạch thực hiện mới là bây giờ:

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

Nếu kế hoạch mới được tin tưởng, sau khi thêm chế độ xem và chỉ mục cụm trên chế độ xem đó, số liệu thống kê xuất hiện cho biết thời gian cần thiết để thực hiện truy vấn hiện đã tăng gấp đôi. Ngoài ra, lưu ý rằng không có đối tượng thống kê mới nào được tạo để hỗ trợ chỉ mục mới sau khi truy vấn được chạy, khác với truy vấn trên bảng.

Kế hoạch truy vấn vẫn cho thấy rằng việc tạo một chỉ mục không bao gồm sẽ khá hữu ích trong việc cải thiện hiệu suất của truy vấn. Vì vậy, điều đó có nghĩa là chỉ số không được bao gồm phải được thêm vào chế độ xem trước khi có thể cải thiện hiệu suất mong muốn? Có một điều cuối cùng để thử. Sửa đổi truy vấn để sử dụng tùy chọn "VỚI NOEXPAND":

SELECT pv.PersistedViewTest_ID, pv.TestComputedColumn
FROM dbo.PersistedViewTest_View pv WITH (NOEXPAND)
WHERE pv.TestComputedColumn = CONVERT(INT, 26)
GO

Điều này dẫn đến kế hoạch truy vấn sau đây:

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

Kế hoạch thực hiện này trông khá giống với kế hoạch được tạo ra với chỉ số không bao gồm trong câu trả lời của Max Vernon. Nhưng, điều này được thực hiện với một chỉ số ít hơn (không bao gồm) và một đối tượng thống kê ít hơn.

Hóa ra tùy chọn NOEXPAND phải được sử dụng với các phiên bản SQL Server tiêu chuẩn và nhanh để sử dụng đúng chế độ xem được lập chỉ mục. Paul White có một bài viết tuyệt vời giải thích về lợi ích của việc sử dụng tùy chọn NOEXPAND. Ông cũng khuyến nghị tùy chọn này được sử dụng với phiên bản doanh nghiệp để đảm bảo đảm bảo tính duy nhất được cung cấp bởi các chỉ mục xem được sử dụng bởi trình tối ưu hóa.

Phân tích trên được thực hiện với phiên bản Express của SQL Sever 2014. Tôi cũng đã thử nó với phiên bản dành cho nhà phát triển của SQL Server 2016. Tùy chọn NOEXPAND dường như không bắt buộc với phiên bản phát triển để đạt được hiệu suất, nhưng vẫn được khuyến nghị .

Chưa đầy 5 tháng trước, Microsoft đã tạo ra các phiên bản dành cho nhà phát triển miễn phí . Giấy phép hạn chế sử dụng chỉ để phát triển, có nghĩa là cơ sở dữ liệu không thể được sử dụng trong môi trường sản xuất. Vì vậy, nếu bạn đang tìm cách kiểm tra các bảng được tối ưu hóa bộ nhớ, mã hóa, R, v.v. thì bạn không còn có lý do không có giấy phép. Tôi đã cài đặt thành công nó trên máy tính của tôi vài ngày trước cùng với SQL Server 2014 Express mà không gặp vấn đề gì.

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.