SQL Server CLR 极速入门,启用、设计、部署、运行

在SQL Server里启用CLR:

在SQL Server里执行以下命名,来启用CLR

EXEC sp_configure 'clr enabled' ,1   --1,启用clr 0,禁用clr
RECONFIGURE WITH OVERRIDE --不加 WITH OVERRIDE在SQL Server 2008 R2上運行不通過
EXEC sp_configure 'clr enabled',1 --1,启用clr 0,禁用clr

RECONFIGURE WITH OVERRIDE --不加 WITH OVERRIDE在SQL Server 2008 R2上運行不通過

用Visual Studio设计功能,并部署到相关数据库:

打开Visual Studio-->新建项目-->数据库-->SQL Server项目-->添加数据库引用里新建链接(一会将会把CLR部署到这个数据库上)-->右击解决方案,添加“用户自定义函数”
这时,系统会生成一个示例文件 Function1.cs 内容:

  1. using System;
  2. using System.Data;
  3. using System.Data.SqlClient;
  4. using System.Data.SqlTypes;
  5. using Microsoft.SqlServer.Server;
  6. public partial class UserDefinedFunctions
  7. {
  8. [Microsoft.SqlServer.Server.SqlFunction]
  9. public static SqlString Function1()
  10. {
  11. // 在此处放置代码
  12. return new SqlString("Hello");
  13. }
  14. };
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里执行我们部署的CLR函数:

再次进入SQL Server,进入到相关数据库,执行 Select dbo.Function1(),全显示执行结果:"Hello"
这个函数你可以在 “数据库-->可编程性-->函数-->标量值函数” 里看到

OK,这就是整个流程,Very Easy.

更高级应用:

当然我们用CLR 不是只为了让他生成一个Hello就完事的,这里来说明一下柳永法(yongfa365)的用途:

去年给公司设计了个OA系统,公司的一些文件内容都非常长,所以选择了varchar(max),初期感觉查询速度还挺快,后来觉得越来越慢。

初步分析结果显示:

  1. 数据有近8000条
  2. 有3000多条数据len(txtContent)得到结果在4000字符以上
  3. 使用“数据库引擎优化顾问”,对其优化提速为"0%"
  4. SQL语句类似:SELECT * FROM dbo.Articles WHERE txtContent LIKE '%柳永法%'
  5. 以前做过的所有系统,从没有遇到这种问题

近一步分析结果:

  1. 数据条数很少,速度却这么慢,分析可能是数据库引擎问题 换台机器试问题依旧,排除
  2. like效率问题,以前的系统都是条数多,而这次遇到的是每条数据里字段内容很长,like除了在数据条数大时会出现性能问题外,还跟每条的字段内容长度有关。在网上查询并测试确认,确实是数据内容长度问题,而这个系统里是不可能使用 like '柳永法%'这样可以使用索引的查询的。

想来想去只能是使用全文索引,但总会有一些记录查不出来,而这个要求就这么高,所以暂时放弃。这时想到了SQL Server CLR,以前只是听过,觉得可能有用,都收藏了起来,现在打开Chrome,把Google Bookmark上收藏的关于SQL Server的CLR的链接全部打开研究了几分钟,自己写了个函数,部署,测试,哈哈……。忒玄妙了,以前的txtContent LIKE '%柳永法%'用时10到12秒,而用我写的SQL Server CLR函数dbo.ContainsOne(txtContent,'柳永法')=1只用了1秒左右,够神奇吧。

执行以下语句三次,相当于8年后数据量,有6万多条数据

  1. INSERT dbo.Articles (txtTitle ,txtContent) SELECT txtTitle , txtContent FROM dbo.Articles
INSERT dbo.Articles (txtTitle ,txtContent) SELECT txtTitle , txtContent  FROM dbo.Articles

再执行测试,一般的 like用时82秒,而clr用时5秒,够有看头吧。

函数及测试语句如下:

  1. [Microsoft.SqlServer.Server.SqlFunction]
  2. public static SqlBoolean ContainsOne(SqlChars input, string search)
  3. {
  4. return new string(input.Value).Contains(search);
  5. }
  6. SELECT COUNT(*) FROM dbo.Articles WHERE dbo.ContainsOne(txtContent,'柳永法')=1
[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);
}

娃哈哈,一切都这么的顺利,这么的得心应手,怎能不让我推荐,在此贴上我写的一此函数:

  1. using System.Data.SqlTypes;
  2. using System.Text.RegularExpressions;
  3. /*
  4. 请先在SQL Server里执行以下命名,来启用CLR
  5. EXEC sp_configure 'clr enabled',1 --1,启用clr 0,禁用clr
  6. RECONFIGURE WITH OVERRIDE
  7. */
  8. namespace CtripSZ.SQLCLR
  9. {
  10. public static partial class UserDefinedFunctions
  11. {
  12. /// <summary>
  13. /// SQL CLR 使用正则表达式替换,eg:
  14. /// select dbo.RegexReplace('<span>柳永法</span>','<.+?>','')
  15. /// update Articles set txtContent=dbo.RegexReplace(txtContent,'<.+?>','')
  16. /// --结果:柳永法
  17. /// </summary>
  18. /// <param name="input">源串,或字段名</param>
  19. /// <param name="pattern">正则表达式</param>
  20. /// <returns>替换后结果</returns>
  21. [Microsoft.SqlServer.Server.SqlFunction]
  22. public static SqlString RegexReplace(SqlChars input, SqlString pattern, SqlString replacement)
  23. {
  24. if (input.IsNull) return null;
  25. return Regex.Replace(input.ToStr(), pattern.Value, replacement.Value);
  26. }
  27. /// <summary>
  28. /// SQL CLR 使用正则表达式替换,eg:
  29. /// select dbo.RegexSearch('<span>柳永法</span>','<.+?>','')
  30. /// select * from Articles where dbo.RegexIsMatch(txtContent,'柳永法')=1;
  31. /// </summary>
  32. /// <param name="input">源串,或字段名</param>
  33. /// <param name="pattern">正则表达式</param>
  34. /// <returns>查询结果,1,0</returns>
  35. [Microsoft.SqlServer.Server.SqlFunction]
  36. public static SqlBoolean RegexIsMatch(SqlChars input, string pattern)
  37. {
  38. if (input.IsNull) return false;
  39. return Regex.IsMatch(input.ToStr(), pattern);
  40. }
  41. /// <summary>
  42. /// SQL CLR 使用.net的Contains查找是否满足条件,eg:
  43. /// select dbo.ContainsOne('我是柳永法,','柳永法');
  44. /// select * from Articles where dbo.ContainsOne(txtContent,'柳永法')=1;
  45. /// </summary>
  46. /// <param name="input">源串,或字段名</param>
  47. /// <param name="search">要搜索的字符串</param>
  48. /// <returns>返回是否匹配,1,0</returns>
  49. [Microsoft.SqlServer.Server.SqlFunction]
  50. public static SqlBoolean ContainsOne(SqlChars input, string search)
  51. {
  52. if (input.IsNull) return false;
  53. return input.ToStr().Contains(search);
  54. }
  55. /// <summary>
  56. /// 實現類似 DateTime.ToString("yyyy-MM-dd");
  57. /// </summary>
  58. /// <param name="input"></param>
  59. /// <param name="format"></param>
  60. /// <returns></returns>
  61. [Microsoft.SqlServer.Server.SqlFunction]
  62. public static SqlString GetDateTimeString(SqlDateTime input, string format)
  63. {
  64. if (input.IsNull) return null;
  65. return input.Value.ToString(format);
  66. }
  67. /// <summary>
  68. /// SQL CLR 使用.net的Contains查找是否满足其中之一的条件,eg:
  69. /// select dbo.ContainsAny('我是柳永法,','柳|永|法');
  70. /// select * from Articles where dbo.ContainsAny(txtContent,'柳|永|法')=1;
  71. /// </summary>
  72. /// <param name="input">源串,或字段名</param>
  73. /// <param name="search">要搜索的字符串,以"|"分隔,自己处理空格问题</param>
  74. /// <returns>返回是否匹配,1,0</returns>
  75. [Microsoft.SqlServer.Server.SqlFunction]
  76. public static SqlBoolean ContainsAny(SqlChars input, string search)
  77. {
  78. if (input.IsNull) return false;
  79. string strTemp = input.ToStr();
  80. foreach (string item in search.Split('|'))
  81. {
  82. if (strTemp.Contains(item))
  83. {
  84. return true;
  85. }
  86. }
  87. return false;
  88. }
  89. /// <summary>
  90. /// SQL CLR 使用.net的Contains查找是否满足所有的条件,eg:
  91. /// select dbo.ContainsAll('我是柳永法,','柳|永|法');
  92. /// select * from Articles where dbo.ContainsAll(txtContent,'柳|永|法')=1;
  93. /// </summary>
  94. /// <param name="input">源串,或字段名</param>
  95. /// <param name="search">要搜索的字符串,以"|"分隔,自己处理空格问题</param>
  96. /// <returns>返回是否匹配,1,0</returns>
  97. [Microsoft.SqlServer.Server.SqlFunction]
  98. public static SqlBoolean ContainsAll(SqlChars input, string search)
  99. {
  100. if (input.IsNull) return false;
  101. string strTemp = input.ToStr();
  102. foreach (string item in search.Split('|'))
  103. {
  104. if (!strTemp.Contains(item))
  105. {
  106. return false;
  107. }
  108. }
  109. return true;
  110. }
  111. /// <summary>
  112. ///
  113. /// </summary>
  114. /// <param name="input"></param>
  115. /// <returns></returns>
  116. public static string ToStr(this SqlChars input)
  117. {
  118. if (input.IsNull) return null;
  119. return new string(input.Value);
  120. }
  121. };
  122. }
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);
        }
    };

}

重要提示:

  1. 官方说明里有其dll部署方法,比较麻烦,推荐直接用Visual Studio部署,方便快捷。
  2. 如果要部署到自己沒權限訪問的機器上,可以先部署到本地,然後在bin\release下找到一個SQL文件,只用此文件便可完成部署,必須使用sqlcmd執行,如:sqlcmd -S .\devdbinstance -U sa -P XXXXXX -i D:\SqlClr\CtripSZ.SQLCLR.sql另:此SQL是根據目標數據庫不同,而不同,使用時要注意
  3. SQL Server CLR 部署到某个数据库后,便成为那个数据库的一部分,即便备份及还原到其它机器上,它依然具有CLR带来的功能。
  4. SqlString 数据类型转换成 nvarchar(4,000),而 SqlChars 转换成 nvarchar(max)。尽可能使用 nvarchar(max) 并且最大程度地保证灵活性。然而,如果所有相关字符串包含的字符都少于 4,000 个,使用 nvarchar(4,000) 则性能可得到显著改善。
  5. CLR里返回的bool对应SQL Server里的bit,即:1/0/Null,而不是true/false,所以,没法直接用dbo.ContainsOne(txtContent,'柳永法')实现bool形,而得这么用:dbo.ContainsOne(txtContent,'柳永法')=1
  6. SQL Server 2005/2008/2008 R2使用的都是CLR 2.0所以,只能选择,2.0,3.0,3.5的.net framework


参考:
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



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值