我有一个这样的表,带有一个计算列:
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
列像保持列一样运行或允许我添加索引的任何想法?!
谢谢!
答案 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)的函数,强制转换为你知道的大小,因为它会表现得更好。