在SQL Server里执行以下命名,来启用CLR
EXEC sp_configure 'clr enabled',1 --1,启用clr 0,禁用clr RECONFIGURE WITH OVERRIDE --不加 WITH OVERRIDE在SQL Server 2008 R2上運行不通過
打开Visual Studio-->新建项目-->数据库-->SQL Server项目-->添加数据库引用里新建链接(一会将会把CLR部署到这个数据库上)-->右击解决方案,添加“用户自定义函数”
这时,系统会生成一个示例文件 Function1.cs 内容:
using System; using System.Data; using System.Data.SqlClient; using System.Data.SqlTypes; using Microsoft.SqlServer.Server; public partial class UserDefinedFunctions { [Microsoft.SqlServer.Server.SqlFunction] public static SqlString Function1() { // 在此处放置代码 return new SqlString("Hello"); } };
现在可以直接右击解决方案,选择“部署”,状态栏里显示“部署已成功”
再次进入SQL Server,进入到相关数据库,执行 Select dbo.Function1(),全显示执行结果:"Hello"
这个函数你可以在 “数据库-->可编程性-->函数-->标量值函数” 里看到
OK,这就是整个流程,Very Easy.
当然我们用CLR 不是只为了让他生成一个Hello就完事的,这里来说明一下柳永法(yongfa365)的用途:
去年给公司设计了个OA系统,公司的一些文件内容都非常长,所以选择了varchar(max),初期感觉查询速度还挺快,后来觉得越来越慢。
初步分析结果显示:
近一步分析结果:
想来想去只能是使用全文索引,但总会有一些记录查不出来,而这个要求就这么高,所以暂时放弃。这时想到了SQL Server CLR,以前只是听过,觉得可能有用,都收藏了起来,现在打开Chrome,把Google Bookmark上收藏的关于SQL Server的CLR的链接全部打开研究了几分钟,自己写了个函数,部署,测试,哈哈……。忒玄妙了,以前的txtContent LIKE '%柳永法%'用时10到12秒,而用我写的SQL Server CLR函数dbo.ContainsOne(txtContent,'柳永法')=1只用了1秒左右,够神奇吧。
执行以下语句三次,相当于8年后数据量,有6万多条数据
INSERT dbo.Articles (txtTitle ,txtContent) SELECT txtTitle , txtContent FROM dbo.Articles
再执行测试,一般的 like用时82秒,而clr用时5秒,够有看头吧。
函数及测试语句如下:
[Microsoft.SqlServer.Server.SqlFunction] public static SqlBoolean ContainsOne(SqlChars input, string search) { return new string(input.Value).Contains(search); } SELECT COUNT(*) FROM dbo.Articles WHERE dbo.ContainsOne(txtContent,'柳永法')=1
另外,我比较热衷于正则表达式,所以我还想给SQL Server增加一个正则表达式替换的功能,写起来也非常容易:
[Microsoft.SqlServer.Server.SqlFunction]
public static SqlString RegexReplace(SqlChars input, SqlString pattern, SqlString replacement)
{
return Regex.Replace(new string(input.Value), pattern.Value, replacement.Value, RegexOptions.Compiled);
}
娃哈哈,一切都这么的顺利,这么的得心应手,怎能不让我推荐,在此贴上我写的一此函数:
using System.Data.SqlTypes; using System.Text.RegularExpressions; /* 请先在SQL Server里执行以下命名,来启用CLR EXEC sp_configure 'clr enabled',1 --1,启用clr 0,禁用clr RECONFIGURE WITH OVERRIDE */ namespace CtripSZ.SQLCLR { public static partial class UserDefinedFunctions { /// <summary> /// SQL CLR 使用正则表达式替换,eg: /// select dbo.RegexReplace('<span>柳永法</span>','<.+?>','') /// update Articles set txtContent=dbo.RegexReplace(txtContent,'<.+?>','') /// --结果:柳永法 /// </summary> /// <param name="input">源串,或字段名</param> /// <param name="pattern">正则表达式</param> /// <returns>替换后结果</returns> [Microsoft.SqlServer.Server.SqlFunction] public static SqlString RegexReplace(SqlChars input, SqlString pattern, SqlString replacement) { if (input.IsNull) return null; return Regex.Replace(input.ToStr(), pattern.Value, replacement.Value); } /// <summary> /// SQL CLR 使用正则表达式替换,eg: /// select dbo.RegexSearch('<span>柳永法</span>','<.+?>','') /// select * from Articles where dbo.RegexIsMatch(txtContent,'柳永法')=1; /// </summary> /// <param name="input">源串,或字段名</param> /// <param name="pattern">正则表达式</param> /// <returns>查询结果,1,0</returns> [Microsoft.SqlServer.Server.SqlFunction] public static SqlBoolean RegexIsMatch(SqlChars input, string pattern) { if (input.IsNull) return false; return Regex.IsMatch(input.ToStr(), pattern); } /// <summary> /// SQL CLR 使用.net的Contains查找是否满足条件,eg: /// select dbo.ContainsOne('我是柳永法,','柳永法'); /// select * from Articles where dbo.ContainsOne(txtContent,'柳永法')=1; /// </summary> /// <param name="input">源串,或字段名</param> /// <param name="search">要搜索的字符串</param> /// <returns>返回是否匹配,1,0</returns> [Microsoft.SqlServer.Server.SqlFunction] public static SqlBoolean ContainsOne(SqlChars input, string search) { if (input.IsNull) return false; return input.ToStr().Contains(search); } /// <summary> /// 實現類似 DateTime.ToString("yyyy-MM-dd"); /// </summary> /// <param name="input"></param> /// <param name="format"></param> /// <returns></returns> [Microsoft.SqlServer.Server.SqlFunction] public static SqlString GetDateTimeString(SqlDateTime input, string format) { if (input.IsNull) return null; return input.Value.ToString(format); } /// <summary> /// SQL CLR 使用.net的Contains查找是否满足其中之一的条件,eg: /// select dbo.ContainsAny('我是柳永法,','柳|永|法'); /// select * from Articles where dbo.ContainsAny(txtContent,'柳|永|法')=1; /// </summary> /// <param name="input">源串,或字段名</param> /// <param name="search">要搜索的字符串,以"|"分隔,自己处理空格问题</param> /// <returns>返回是否匹配,1,0</returns> [Microsoft.SqlServer.Server.SqlFunction] public static SqlBoolean ContainsAny(SqlChars input, string search) { if (input.IsNull) return false; string strTemp = input.ToStr(); foreach (string item in search.Split('|')) { if (strTemp.Contains(item)) { return true; } } return false; } /// <summary> /// SQL CLR 使用.net的Contains查找是否满足所有的条件,eg: /// select dbo.ContainsAll('我是柳永法,','柳|永|法'); /// select * from Articles where dbo.ContainsAll(txtContent,'柳|永|法')=1; /// </summary> /// <param name="input">源串,或字段名</param> /// <param name="search">要搜索的字符串,以"|"分隔,自己处理空格问题</param> /// <returns>返回是否匹配,1,0</returns> [Microsoft.SqlServer.Server.SqlFunction] public static SqlBoolean ContainsAll(SqlChars input, string search) { if (input.IsNull) return false; string strTemp = input.ToStr(); foreach (string item in search.Split('|')) { if (!strTemp.Contains(item)) { return false; } } return true; } /// <summary> /// /// </summary> /// <param name="input"></param> /// <returns></returns> public static string ToStr(this SqlChars input) { if (input.IsNull) return null; return new string(input.Value); } }; }
重要提示:
参考:
SQL Server CLR 集成简介:http://msdn.microsoft.com/zh-cn/library/ms254498(VS.80).aspx
SQL Server 2005 正则表达式使模式匹配和数据提取变得更容易:http://msdn.microsoft.com/zh-cn/magazine/cc163473.aspx
SQLCLR(一)入门:http://www.cnblogs.com/DavidFan/archive/2007/05/08/738557.html
应用C#和SQLCLR编写SQL Server用户定义函数:http://blog.csdn.net/zhzuo/archive/2009/05/24/4212982.aspx#mark4