2012-01-31 19 views
5

Tôi có một bảng như thế này với một cột tính:Không thể thêm chỉ số để tồn cột tính vì nó là "của một loại đó là không hợp lệ để sử dụng như một chìa khóa"

CREATE TABLE PhoneNumbers 
(
    [PhoneNumberID] int identity(1,1) not null primary key clustered, 
    [Number] varchar(20), /* Entire number, like (800) 555-5000 */ 
    [Digits] AS dbo.RegExReplace(Number, '[^0-9]', '') PERSISTED /* Like 8005555000 */ 
) 

Nó tạo tốt, và cột Digits hoạt động tốt như mong đợi, NHƯNG nó dường như không hoạt động như một cột "ĐÃ ĐƯỢC". Khi tôi làm một truy vấn với Digits trong mệnh đề WHERE nó rất chậm. Khi tôi cố gắng thêm chỉ mục vào cột Chữ số, tôi nhận được: Column 'Digits' in table 'PhoneNumbers' is of a type that is invalid for use as a key column in an index.

Có vẻ như cột đó không thực sự được coi là PERSISTED và đang được tính toán lại trên mọi truy vấn và sẽ không cho phép tôi thêm chỉ mục.

Các REGEXREPLACE là một C# CLR chức năng được xác định như sau:

[SqlFunction(IsDeterministic = true, IsPrecise = true)] 
public static SqlString RegExReplace(SqlString expression, SqlString pattern, SqlString replace) 

Bất kỳ ý tưởng về làm thế nào để có được điều đó Digits cột để hành động như một cột tiếp tục tồn tại hoặc cho phép tôi thêm một chỉ số ?!

Cảm ơn bạn!

+1

Tôi sẽ không thiết kế như vậy. Tôi sẽ không lưu trữ bất cứ thứ gì trừ chữ số và tôi sẽ sử dụng giao diện người dùng để thực thi bất kỳ mẫu nào. Đó là overdesign, IMO. –

+0

Vâng, có thể bạn đã đúng, nhưng đây là cơ sở dữ liệu kế thừa có nhiều bản ghi đã có trong đó và nhiều điểm vào cho các bản ghi này. Tôi nghĩ đây có thể là một bản vá dễ dàng hơn để có được những con số mà không cần phải thay đổi mã ở 10 địa điểm khác nhau. (Cột "Chữ số" thực sự là một cột mới, không phải là một phần của thiết kế ban đầu) – JerSchneid

Trả lời

6

Thử CAST:

CREATE TABLE PhoneNumbers 
(
    [PhoneNumberID] int identity(1,1) not null primary key clustered, 
    [Number] varchar(20), /* Entire number, like (800) 555-5000 */ 
    [Digits] AS CAST(dbo.RegExReplace(Number, '[^0-9]', '') AS VARCHAR(20)) PERSISTED /* Like 8005555000 */ 
) 

Tôi tin rằng vấn đề là chức năng CLR của bạn đang trở lại SqlString mà kết thúc lên được nvarchar (4000) hoặc tương tự - không lập chỉ mục.

Đó là loại "sự cố" đã biết với các cột được tính toán mà kiểu dữ liệu được suy ra từ biểu thức. Chủ yếu là một vấn đề với chuỗi và "chức năng trợ giúp" mà có varchar (tối đa) và cũng với các hoạt động thập phân, nơi chính xác thay đổi do tính toán.

Tôi có một quy tắc nhỏ mà tôi luôn luôn CAST - nó làm cho nó rõ ràng và tránh bất kỳ sự mơ hồ nào. Nói chung, các cột được biết là nhỏ nên rõ ràng nhỏ - varchar (max) dường như có rất nhiều hiệu suất trên không - ngay cả khi bạn vượt qua một hàm trả về varchar (max) và lấy varchar (max), cast trở lại kích thước bạn biết, bởi vì nó sẽ thực hiện tốt hơn rất nhiều.

+0

Wow ... Câu trả lời thú vị! Tôi đã thực sự tìm kiếm làm thế nào tôi có thể tuyên bố rằng cột tính toán được của một loại nhất định, nhưng không xem xét một diễn viên đơn giản. Nó thực sự KHÔNG giải quyết lỗi "không hợp lệ cho cột khóa" và tôi có thể thêm chỉ mục, nhưng hiệu suất vẫn khủng khiếp khi tìm kiếm trên cột đó? Tôi hiện đang xem xét việc cắn viên đạn và thiết kế lại cột "Số" để chỉ chứa các chữ số. Cám ơn rất nhiều! Bạn đá! – JerSchneid

+0

@ JerSchneid Tôi không chắc tại sao hiệu suất lại tệ - hãy kiểm tra kế hoạch thực hiện của bạn, tất nhiên. Khi cột được duy trì, nó không nên gọi hàm CLR của bạn. Có lẽ nó không sử dụng chỉ mục đầu tiên do một số thứ khác trong truy vấn? Chỉ mục của bạn có chứa cột được duy trì liên tục không? –

+0

Kế hoạch thực hiện dường như không cho tôi bất kỳ thông tin nào ... Các truy vấn đơn giản bằng đá như "SELECT * FROM from PhoneNumbers WHERE Digits = '8005552000'" không sử dụng bất kỳ chỉ mục nào tôi tạo bao gồm cột. Không biết tại sao? – JerSchneid

Các vấn đề liên quan