ngăn toán tử chèn chỉ mục cụm trên chế độ xem chỉ mục không đủ tiêu chuẩn


8

Có ai biết một cách giải quyết cho điều này? Về cơ bản, thủ tục được lưu trữ buộc một toán tử chèn chống lại khung nhìn được lập chỉ mục, mặc dù các hàng không đủ điều kiện. Kết quả là có một lỗi cast. Tuy nhiên, đối với hocs quảng cáo, sql loại bỏ chính xác chế độ xem khỏi xem xét.

Hãy xem xét lược đồ sau:

create table testdata (
    testid int identity(1,1) primary key
  , kind varchar(50)
  , data nvarchar(4000))
go
create view integer_testdata with schemabinding
as
select cast(a.data as int) data, a.kind, a.testid
  from dbo.testdata a
 where a.kind = 'integer'
go
create unique clustered index cl_intdata on integer_testdata(data)
go
create procedure insert_testdata
(
    @kind varchar(50)
  , @data nvarchar(4000)
)
as
begin
  insert into testdata (kind, data) values (@kind, @data)
end
go

Tất cả đều hoạt động:

insert into testdata (kind, data) values ('integer', '1234');
insert into testdata (kind, data) values ('integer', 12345);
insert into testdata (kind, data) values ('noninteger', 'noninteger');
exec insert_testdata @kind = 'integer', @data = '123456';
exec insert_testdata @kind = 'integer', @data = 1234567;

Điều này không thành công:

exec insert_testdata @kind = 'noninteger', @data = 'noninteger';

So sánh "kế hoạch thực hiện ước tính":

insert into testdata (kind, data) values ('noninteger', 'noninteger'): nhập mô tả hình ảnh ở đây

exec insert_testdata @kind = 'noninteger', @data = 'noninteger': nhập mô tả hình ảnh ở đây


Bất kỳ sự khác biệt đáng chú ý giữa kế hoạch Proc lưu trữ ad hoc và lưu trữ trên mỗi cơ hội?
Ali Razeghi

vâng, khi bạn thực hiện ad hoc, bạn không nhận được bất kỳ toán tử nào chống lại chế độ xem được lập chỉ mục ... Tôi nghĩ rằng sql đủ thông minh để xem có một bộ lọc trên chế độ xem và loại bỏ nó khỏi xem xét (việc loại bỏ này không xảy ra trong Proc)
cocogorilla

4
Không ở vị trí để kiểm tra nhưng có thêm option (recompile)trợ giúp?
Martin Smith

2
Chỉ cần tò mò, bạn đang cố gắng giải quyết vấn đề gì. Điều này có mùi giống như một vấn đề XY .
Max Vernon

1
@MaxVernon Tôi đang làm việc với cấu trúc dữ liệu hiện có và cần tra cứu nhanh các giá trị số nguyên duy nhất được lưu trữ trong tập hợp con của nvarchar (4000), một bộ lọc trên một cột khác xác định tập hợp con các hàng đó.
cocogorilla

Câu trả lời:


6

Cảm ơn bạn đã cung cấp một kịch bản đầy đủ để tạo lại vấn đề.

Tôi đã thử nghiệm nó với SQL Server 2014 Express.

Khi tôi thêm OPTION(RECOMPILE)nó hoạt động:

ALTER procedure [dbo].[insert_testdata]
(
    @kind varchar(50)
  , @data nvarchar(4000)
)
as
begin
  insert into testdata (kind, data) 
  values (@kind, @data)
  OPTION(RECOMPILE);
end

Khi tôi chạy cái này trong SSMS:

exec insert_testdata @kind = 'noninteger', @data = 'noninteger';

Tôi nhận được tin nhắn này:

(1 row(s) affected)

và một hàng được thêm vào bảng.

Phiên bản SQL Server nào bạn đang sử dụng? Tôi mơ hồ nhớ rằng trong các phiên bản trước năm 2008, OPTION(RECOMPILE)hành vi này hơi khác một chút.


Tôi đang làm việc với cấu trúc dữ liệu hiện có và cần tra cứu nhanh các giá trị số nguyên duy nhất được lưu trữ trong tập hợp con của nvarchar (4000), một bộ lọc trên cột khác xác định tập hợp con các hàng đó.

Trong trường hợp này, có thể tốt hơn để sử dụng chỉ mục được lọc thay vì chế độ xem được lập chỉ mục:

CREATE UNIQUE NONCLUSTERED INDEX [IX_DataFiltered] ON [dbo].[testdata]
(
    [data] ASC
)
WHERE ([kind]='integer')

Trình tối ưu hóa nên sử dụng chỉ mục này khi WHEREbộ lọc của truy vấn khớp chính xác với WHEREmệnh đề của chỉ mục.

Có, ở đây chỉ mục nằm trên nvarcharcột có thể không phải là điều tốt nhất, đặc biệt nếu bạn tham gia bảng này với một intcột của bảng khác hoặc cố gắng lọc các giá trị trong cột này bằng intcác giá trị.


Một biến thể khác mà tôi nghĩ đến là cột được tính toán bền bỉ chuyển đổi nvarcharthành int. Về bản chất, nó rất giống với chế độ xem của bạn, nhưng các nvarchargiá trị bền vững được chuyển đổi thành intđược lưu trữ với cùng một bảng, không phải trong một đối tượng riêng biệt.

CREATE TABLE [dbo].[testdata](
    [testid] [int] IDENTITY(1,1) NOT NULL,
    [kind] [varchar](50) NULL,
    [data] [nvarchar](4000) NULL,
    [int_data]  AS (case when [kind]='integer' then CONVERT([int],[data]) end) PERSISTED,
PRIMARY KEY CLUSTERED 
(
    [testid] ASC
))


CREATE UNIQUE NONCLUSTERED INDEX [IX_int_data_filtered] ON [dbo].[testdata]
(
    [int_data] ASC
)
WHERE ([kind]='integer')

Với thiết lập này, tôi đã cố gắng sử dụng quy trình được lưu trữ ban đầu của bạn để chèn các hàng và nó hoạt động ngay cả khi không có OPTION(RECOMPILE).


Trên thực tế, có vẻ như lý do chính tại sao cột tồn tại ở trên hoạt động là do tôi sử dụng CASE. Nếu tôi thêm CASEvào định nghĩa của chế độ xem của bạn, quy trình được lưu trữ sẽ hoạt động mà không có OPTION(RECOMPILE).

create view integer_testdata2 with schemabinding
as
select 
    case when a.kind='integer' then CONVERT(int, a.data) end as data
    , a.kind, a.testid
from dbo.testdata a
where a.kind = 'integer'
go

Tôi không chắc chỉ mục được lọc sẽ hoạt động tốt vì chiều rộng cột là 4000 (vượt quá giới hạn 900). Tôi đã không nghĩ đến việc sử dụng tùy chọn gợi ý truy vấn biên dịch lại ... Tôi đang áp dụng biên dịch lại cho toàn bộ quy trình. Đề nghị của bạn làm việc cho tất cả các trường hợp thử nghiệm của tôi! Cảm ơn bạn.
cocogorilla

1
Có, chỉ mục được lọc trên cột ban đầu có thể không hữu ích lắm. Tôi đã thêm một biến thể khác với cột tính toán bền bỉ.
Vladimir Baranov

Tôi thích tùy chọn cột được tính toán bền bỉ ... đó là một giải pháp chính xác
cocogorilla
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.