正则表达式与SQL Server 2008 CLR性能问题

时间:2015-07-07 19:51:47

标签: regex sql-server-2008 sqlclr

我试图理解为什么执行一个简单的查询需要这么长时间。 在我的本地机器上需要10秒钟,但在生产中需要1分钟。 (我将数据库从生产导入我的本地数据库)

select * 
from JobHistory
where dbo.LikeInList(InstanceID, 'E218553D-AAD1-47A8-931C-87B52E98A494') = 1

DataHistory未编入索引,且有217,302行

public partial class UserDefinedFunctions
{
    [SqlFunction]
    public static bool LikeInList([SqlFacet(MaxSize = -1)]SqlString value, [SqlFacet(MaxSize = -1)]SqlString list)
    {
        foreach (string val in list.Value.Split(new char[] { ',' }, StringSplitOptions.None))
        {
            Regex re = new Regex("^.*" + val.Trim() + ".*$", RegexOptions.IgnoreCase);

            if (re.IsMatch(value.Value))
            {
                return(true);
            }
        }

        return (false);
    }
};

问题是,如果一个表有217k行,那么我将调用该函数217,000次!不知道如何重写这件事。

谢谢

1 个答案:

答案 0 :(得分:1)

此代码存在以下几个问题:

  1. (IsDeterministic = true, IsPrecise = true)属性中缺少[SqlFunction]。这样做(主要只是IsDeterministic = true部分)将允许SQLCLR UDF参与并行执行计划。如果不设置IsDeterministic = true,此函数将阻止并行计划,就像T-SQL UDF一样。
  2. 返回类型为bool,而不是SqlBoolean
  3. RegEx调用效率低下:使用实例方法一次是昂贵的。切换到使用静态Regex.IsMatch而不是
  4. RegEx模式非常效率低下:将搜索字符串包装在“^。*”和“。* $”中将需要RegEx引擎解析对于value的每次迭代,在内存中保留为“匹配”,即foreach输入参数的全部内容。然而,正则表达式的行为使得仅使用val.Trim()作为整个模式将产生完全相同的结果

  5. (可选)如果 输入参数都不会超过4000个字符,则指定MaxSize 4000代替-1,因为{将数据传入和传出SQLCLR对象比NVARCHAR(4000)快得多。