无法将索引添加到持久计算列,因为它是“无法用作键的类型”

时间:2012-01-31 02:46:13

标签: sql sql-server clr

我有一个这样的表,带有一个计算列:

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 */
)

它创建得很好,Digits列的工作效果很好,但它看起来并不像“PERSISTED”列。当我在WHERE子句中使用Digits进行查询时,它非常慢。当我尝试向Digits列添加索引时,我得到:Column 'Digits' in table 'PhoneNumbers' is of a type that is invalid for use as a key column in an index.

似乎该列实际上并未被视为PERSISTED,并且正在重新计算每个查询,并且不会让我添加索引。

RegExReplace是一个C#CLR函数,定义如下:

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

有关如何让Digits列像保持列一样运行或允许我添加索引的任何想法?!

谢谢!

1 个答案:

答案 0 :(得分:6)

尝试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 */
)

我认为问题是你的CLR函数正在返回SqlString,它最终是nvarchar(4000)或类似的 - 不可索引。

这是计算列的已知“问题”,数据类型是从表达式推断出来的。主要是字符串和“辅助函数”的问题,它采用varchar(max)以及由于计算导致精度发生变化的十进制运算。

我有一个小规则,我总是CAST - 它使它明确,避免任何歧义。通常,已知较小的列应该显式小 - varchar(max)似乎有很多性能开销 - 即使您通过返回varchar(max)并接受varchar(max)的函数,强制转换为你知道的大小,因为它会表现得更好。