zoukankan      html  css  js  c++  java
  • 用Clr实现的sql表值函数splitIDs

     在我们需要批量删除数据,或者批量修改实体的状态时,为了性能我们会直接写一个存储过程,并将这一批数据的id用“,”分隔传递给一个存储过程,然后在存储过程中拆分这个字符串,然后执行删除或者更新状态操作。以前每次执行这种操作时我都会在存储过程中拆分字符串。现在sql server支持用.net clr的程序集写函数,存储过程等等。 

    现在我们就牛刀小试,做一个clrsql表值函数。该函数的功能就是传入一个用逗号分隔的数字id字符,返回一个只有一列id的表。
    第一步:我们需要新建一个类库项目,并添加一个类SplitIDs

    using System;
    using System.Collections.Generic;
    using System.
    Text;
    using Microsoft.SqlServer.Server;
    using System.Collections;
    using System.Data.SqlTypes;

    public class SplitIDs
    {
        
    [SqlFunction(FillRowMethodName = "FillRow")]
        
    public static IEnumerable DoSplit(String strIDs)
        {
            
    return strIDs.Split(',');
        }

        
    public static void FillRow(Object obj, out SqlInt64 id)
        {
            
    long value = 0;
            
    long.TryParse((string)obj, out value);
            id 
    = new SqlInt64(value);
        }
    }

    2个注意的点
    1.     命名空间声明要去掉,我在测试的过程中刚开始有命名空间的声明,总是注册不成功,后来去掉了存储过程的声明,才注册上
    2.     方法必须是静态的并且要有SqlFunction特性,表值函数的返回值是IEnurable

    第二步:注册程序集到sql server

    USE [DB_Name]
    GO
    if (object_id('SplitIDs'is not null)
    drop function splitIds;
    GO
    IF  EXISTS (SELECT * FROM sys.assemblies asms WHERE asms.name = N'SqlServerUtility')
    DROP ASSEMBLY [SqlServerUtility]
    go
    CREATE ASSEMBLY SqlServerUtility 
    FROM 'D:\Program Files\Microsoft SQL Server\90\UserDefinedAssembly\SqlServerUtility.dll' 
    WITH PERMISSION_SET = SAFE
    GO
    CREATE FUNCTION SplitIDs(@ids Nvarchar(max))
    RETURNS TABLE (id bigint)
    AS 
    EXTERNAL NAME SqlServerUtility.SplitIDs.DoSplit
    GO
    EXEC sp_configure "clr enabled",1   
    RECONFIGURE
    GO

    注册过程中需要注意的是上面注册sql中的最后一块,配置在数据库中启用clr enabled属性。否则即使注册上了函数也不能执行。
    注册好了,我们来一个小例子,测试一下函数的执行情况:
    select * from splitIDs('1,2,9,1000');
    select * from splitIDs('333');
    select * from splitIDs(NULL);
    执行结果一切正常。
    -------------t-sql实现分隔------------
    当然这个函数还可以用t-sql直接实现,实现代码如下:

    Use DB_Name
    GO
    if (object_id('splitIds'is not null)
    drop function splitIds;
    GO
    CREATE FUNCTION splitIds(
        
    @strIds varchar(max
    )
    RETURNS @IDs table (id bigint)
    AS
    BEGIN 
        
    declare @i int,@j int,@l int,@v bigint;
        
    SET @i = 0;
        
    SET @j = 0;
        
    SET @l = len(@strIds);
        
    while (@j < @l)
        
    BEGIN
            
    SET @j = charindex(',',@strIds,@i+1);
            
    IF @j = 0 set @j = @l+1;
            
    SET @v = cast(substring(@strIds,@i+1,@j-@i-1as bigint);
            
    INSERT INTO @IDs(id)VALUES(@v)
            
    SET @i = @j;
        
    END
        
    RETURN ;
    END
    GO

    最后测试一下用clr实现和sql直接实现的性能差别;我们声明一个很长的字符串变量,然后让clr的splitIDs和t-sql的splitIDs分别做拆分10次,比较他们的耗时

    测试脚本 (在测试脚本中使用的函数名字分别是splitIDs_tsql,splitIDs_clr

    t-sql和clr实现的性能比较
    执行的结果是:
    splitIDs_tsql执行时间10060
    splitIDs_clr执行时间266

    很明显,用clr写的拆分函数要比tsql的拆分函数快大约50倍。

    全文结束
  • 相关阅读:
    [TC11326]ImpossibleGame
    [CC-FNCS]Chef and Churu
    [JZOJ4786]小a的强迫症
    [USACO08NOV]Time Management
    ARC070F HonestOrUnkind
    LOJ2799 「CCC 2016」生命之环
    Luogu P5824 十二重计数法(小球盒子计数)
    Luogu P4249 [WC2007]剪刀石头布
    Kattis heapsoffun Heaps of Fun
    Kattis xorsequences XOR Sequences
  • 原文地址:https://www.cnblogs.com/yukaizhao/p/clr_sql_function.html
Copyright © 2011-2022 走看看