在SQL Server 2014上崩溃CLR(Windows 2012R2)


12

我有这个小的CLR,它对列中的字符串执行RegEX功能。

在Windows Server 2012R2的SQL Server 2014(12.0.2000)上运行时,该进程崩溃

消息0,级别11,状态0,行0当前命令发生严重错误。结果(如有)应丢弃。

并给我一个堆栈转储

select count (*) from table where (CLRREGEX,'Regex')

但是当我这样做

select * from table where (CLRREGEX,'Regex') 

它返回行。

可以在Windows 8.1上运行的同一SQL Server版本上完美运行。

有任何想法吗?

-编辑尽可能简单

using System;
using System.Collections.Generic;
using System.Text;
using System.Data.SqlTypes;           //SqlString, SqlInt32, SqlBoolean
using System.Text.RegularExpressions; //Match, Regex
using Microsoft.SqlServer.Server;     //SqlFunctionAttribute
public partial class UserDefinedFunctions
{
    public static readonly RegexOptions Options = RegexOptions.IgnorePatternWhitespace | RegexOptions.Multiline;
    [SqlFunction]
    [Microsoft.SqlServer.Server.SqlFunction(IsDeterministic = true, IsPrecise = true)]
    public static SqlBoolean RegExMatch(SqlString input, SqlString pattern)
    {
        if (input.IsNull || pattern.IsNull) //nulls dont qualify for a match
            return SqlBoolean.False;
    return Regex.IsMatch(input.Value, pattern.Value, RegexOptions.IgnoreCase);
    }
}

因此,只需稍作更改,便可以正常工作:C#中的主要课程似乎与TSQL中的相同,请注意隐式数据转换。

using System;
using System.Text;
using System.Data.SqlTypes;           //SqlString, SqlInt32, SqlBoolean
using System.Text.RegularExpressions; //Match, Regex
using Microsoft.SqlServer.Server;     //SqlFunctionAttribute
public partial class UserDefinedFunctions
{
public static readonly RegexOptions Options = RegexOptions.IgnorePatternWhitespace | RegexOptions.Singleline | RegexOptions.Compiled | RegexOptions.IgnoreCase | RegexOptions.CultureInvariant;

    [Microsoft.SqlServer.Server.SqlFunction(IsDeterministic = true, IsPrecise = true, DataAccess = DataAccessKind.Read)]
    public static SqlBoolean RegExMatch(SqlString input, SqlString pattern)
{
    if (input.IsNull || pattern.IsNull) //nulls dont qualify for a match
        return SqlBoolean.False;
    string sqldata = input.ToString();
    string regex = pattern.ToString();
    return Regex.IsMatch(sqldata, regex);
 }

这是针对所有模式还是仅针对此模式发生?这可能是效率低下的模式(即过多的回溯或不必要的捕获)。您应该研究设置MatchTimeout属性(.NET Framework 4.5中的新增功能)。您是否自己编写了RegEx函数的代码?如果是这样,您是否使用静态或实例RegEx方法?该SqlFunction方法是否标记为IsDeterministic=true?程序集是否标记为SAFE
所罗门·鲁茨基

2
这些桌子有多大?另外,您可以检查问题陈述的估计计划是否具有并行运算符?如果是,是否可以在没有并行性的情况下检查问题是否发生,即具有MAXDOP = 1提示。
阿米特·班纳吉

2
该代码看起来不错,但重复[SqlFunction]属性除外。那是确切的代码吗?我认为不会编译。框架版本2.0 / 3.0 / 3.5的区别不是问题,因为您使用的是4.0 / 4.5 / 4.5.x / etc或该服务器上的任何内容,因为您使用的是绑定到CLR版本4的SQL Server 2014。服务器显示问题的32位?与其他服务器相比,它有多少内存?并且在收到该错误后是否检查了SQL Server日志?
所罗门·鲁兹基

2
.NET的确切版本与问题无关,尽管很高兴知道所有服务器是否均在4.5以上,因为这意味着您可以使用new MatchTimeout属性。但是,如果您最多传入5个字符,我也不认为这是真正的问题。这可能的,这种一体机有一个损坏的安装.NET Framework的,而一旦钓鳟鱼的活动已经停止;-)可以修复。同样,它[0-9].*很简单,但效率也很低,因为它匹配第一个数字后的所有字符(如果有);只[0-9]使用一个IsMatch更好。
所罗门·鲁兹基

1
你为什么要改变DataAccessKindRead?这只会减慢速度,并且您没有进行任何数据访问。另外,我确实意识到它现在似乎可以正常工作,但是我会谨慎使用ToString()方法而不是Value属性,因为我认为ToString无法正确处理编码或类似的东西。您的数据库排序规则设置为什么?当然,我只是重新阅读了您上面的评论之一,然后看到该列是VARCHAR而不是NVARCHAR。该字段的排序规则与数据库是否不同?
所罗门·鲁兹基

Answers:


4

问题是Windows操作系统和SQL Server(特别是程序集加载所在的数据库)之间的语言环境冲突。您可以运行以下查询以查看它们都设置为:

SELECT os_language_version,
       DATABASEPROPERTYEX(N'{name of DB where Assembly exists}', 'LCID') AS 'DatabaseLCID'
FROM   sys.dm_os_windows_info;

如果它们不同,那么您肯定会得到一些“奇怪”的行为,例如您所看到的。问题是:

  • SqlString不仅包括文本本身,还包括:程序集所在数据库的默认排序规则。排序规则由两部分信息组成:语言环境信息(即LCID)和比较选项(即SqlCompareOptions),它们详细说明了对大小写,重音,假名,宽度或所有内容(二进制和二进制2)的敏感性。
  • 除非明确指定语言环境,否则.NET中的字符串操作将使用当前线程的语言环境信息,该信息是在Windows(即操作系统/ OS)中设置的。

当引用SqlString参数而不使用.Value.ToString()进行隐式转换为时,通常会发生冲突SqlString。在这种情况下,将导致异常,指出LCID不匹配。

显然还有其他情况,例如执行(某些/全部?)字符串比较,包括在这种情况下使用Regex时(尽管到目前为止,我还无法重现此内容)。

修复建议:

理想的(比较的工作方式总是可以满足的期望):

  • 更改Windows或SQL Server LCID(默认语言),以便两者匹配

不太理想(Windows区域设置的行为对于相等性和排序可能没有相同的规则,因此可能会出现意外结果):

  • 使用.ToString方法或.Value属性,它们都返回不带SQL Server LCID的字符串,因此所有操作都将使用OS LCID。

可能有帮助:

  • 可能使用SqlChars而不是,SqlString因为它不会带来来自SQL Server的LCID和排序规则信息
  • 通过StringComparison.InvariantCulture以下命令指定文化无关紧要:
    • String.Compare(string, string, StringComparison.InvariantCulture) 要么 String.Compare(string, string, StringComparison.InvariantCultureIgnoreCase)
    • 对于正则表达式,请指定 RegexOptions.CultureInvariant

1

更新..

@srutzky指出,SQL引擎和窗口服务器之间的本地化不同:

os_language_version SqlServerLCID
1033 1039

代码的以下更改-设置选项可避免RegexOptions.CultureInvariant错误。不变的代码不会在使用相同语言设置的Windows Server 2012R2上使SQL Server 2012崩溃,但在SQL Server 2014上会这样做。

using System;
using System.Text;
using System.Data.SqlTypes;           //SqlString, SqlInt32, SqlBoolean
using System.Text.RegularExpressions; //Match, Regex
using Microsoft.SqlServer.Server;     //SqlFunctionAttribute
public partial class UserDefinedFunctions
{
public static readonly RegexOptions Options = RegexOptions.IgnorePatternWhitespace | RegexOptions.Singleline | RegexOptions.Compiled | RegexOptions.IgnoreCase | RegexOptions.CultureInvariant;

    [Microsoft.SqlServer.Server.SqlFunction(IsDeterministic = true, IsPrecise = true)]
    public static SqlBoolean RegExMatch(SqlString input, SqlString pattern)
{
    if (input.IsNull || pattern.IsNull) //nulls dont qualify for a match
        return SqlBoolean.False;
    string sqldata = input.ToString();
    string regex = pattern.ToString();
    return Regex.IsMatch(sqldata, regex);
 }

您能否在崩溃的服务器上运行以下命令:SELECT os_language_version, SERVERPROPERTY('LCID') AS 'SqlServerLCID' FROM sys.dm_os_windows_info;。问题很有可能是语言设置方面的冲突。您的解决方案可能仍然是最好的方法,但是通常不需要使用ToString()代替s 上的Value属性SqlString。因此,确认情况将很不错。
所罗门·鲁兹基2015年

我发布了一个答案进行澄清,但是由于您没有将变量传递到中,因此不应通过设置解决问题。在原始代码和新的有效代码之间发生的变化是,您从使用转到了。我怀疑如果切换到使用,您会看到相同的固定行为。但是我只是做一个测试。最好的方法是更改​​Windows或SQL Server的LCID以使其相互匹配。您也可以删除“选项”静态变量。RegexOptions.CultureInvariantOptionsRegex.IsMatch(sqldata, regex)SqlString.ValueSqlString.ToString()SqlChars
所罗门·鲁兹基

嗨,您好。感谢您接受我的回答:)。只是说,我进行了进一步的研究,如果理解了我所看到的内容,那么虽然我对根本原因是操作系统和SQL Server之间的LCID不同的说法是正确的,但它与该.Value属性没有或不应该相关的SqlString作为显然返回相同的内部的值作为.ToString()方法。我仍在调查中,将使用发现的任何内容更新我的答案:)。
所罗门·鲁兹基2015年

我根据新信息调整了答案。我无法重现这种情况。问题中的代码真的是您正在/正在使用的吗?它们之间的唯一真正区别是,一个错误使用了一个错误RegexOptions.IgnoreCase而另一个没有使用。我已经建立了一个类似的环境:Windows(8.0)使用的LCID为1033,SQL Server DB的LCID为1039,使用与您发布的相同的RegEx,COUNT(*)VARCHAR填充GUID 的字段上执行'[0-3â].*',在表上使用的模式一千万行。它是SQL Server 2012,而不是2014,尽管我认为这并不重要。
所罗门·鲁兹基

1
感谢所有的答案。问题中的代码是我正在使用的代码。我有一个非常复杂的正则表达式,但使用一个非常简单的正则表达式设法使它崩溃。更改RegexOptions.CultureInvariant设置来停止的行为
Spörri
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.