SQL Server 2014(Windows 2012R2)でのCLRのクラッシュ


12

列内の文字列に対してRegEX関数を実行するこの小さなCLRがあります。

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]属性を除いて、コードは正常に見えます。それは正確なコードですか?私はそれがコンパイルされるとは思わない。Frameworkバージョン2.0 / 3.0 / 3.5の区別は、CLRバージョン4にバインドされているSQL Server 2014を使用しているため、4.0 / 4.5 / 4.5.x /などまたはそのサーバー上にあるものを使用しているため、問題ではありません。サーバーは問題の32ビットを表示していますか?他のサーバーと比較してどのくらいのメモリがありますか?また、そのエラーが発生した直後にSQL Serverログを確認しましたか?
ソロモンラッツキー

2
.NETの正確なバージョンは問題に関連していませんが、新しいMatchTimeoutプロパティを使用できることを意味するため、すべてのサーバーが少なくとも4.5にあるかどうかを知ることは良いことです。ただし、最大で5文字しか渡さない場合、これが実際に問題になるとは思わない ある、この1台のマシンが、.NET Frameworkのインストール破損している可能性があり、鱒漁業活動が;-)終わったらそれを修復することができます。また、[0-9].*シンプルですが、最初の桁以降のすべての文字が存在する場合は一致するため、非効率的です。だけ[0-9]に使用するIsMatch方が良いです。
ソロモンラッツキー

1
なぜに変わっDataAccessKindたのReadですか?それはただそれを遅くし、データアクセスをしていません。また、私はそれが今働いているように見えることを理解していますが、ToStringがエンコーディングなどを適切に処理するとは思わないToString()ため、Valueプロパティではなくメソッドを使用することに注意します。データベース照合は何に設定されていますか?もちろん、上記のコメントの1つを読み直したところ、列がNVARCHARではなくVARCHARであることがわかりました。そのフィールドには、データベースとは異なる照合順序がありますか?
ソロモンラッツキー

回答:


4

問題は、Windows OSと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)と、大文字と小文字、アクセント、仮名、幅、またはすべて(binaryとbinary2)の区別を詳述する比較オプション(SqlCompareOptions)の2つの情報で構成されます。
  • .NETの文字列操作では、明示的にロケールを指定しない限り、Windows(つまり、オペレーティングシステム/ OS)で設定されている現在のスレッドのロケール情報を使用します。

通常、競合は、を使用せずにSqlStringパラメーターを参照する場合、.Valueまたはに.ToString()暗黙的に変換する場合に発生しSqlStringます。その場合、LCIDが一致しないという例外が発生します。

このケースが示すようにRegexを使用する場合(これまでのところ、これを再現することはできませんでした)を含め、(一部/すべて?)文字列比較を実行するなど、明らかに他のシナリオがあります。

修正のためのいくつかのアイデア:

理想的(比較の仕組みに関する期待は常に満たされます):

  • WindowsまたはSQL Server LCID(デフォルト言語)を変更して、両方が一致するようにします

理想的とは言えません(Windowsロケールの動作は、同等性とソートのルールと同じではない可能性があるため、予期しない結果になる可能性があります)。

  • .ToStringメソッドまたは.Valueプロパティを使用します。どちらもSQL Server LCIDなしで文字列を返すため、操作はすべてOS LCIDを使用します。

役立つかもしれません:

  • SQL ServerからLCIDと照合情報を持ち込まないため、SqlChars代わりに使用する可能性SqlStringがあります
  • カルチャが重要でないことを指定するには、次を使用し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;。問題が言語設定の競合であった可能性は十分にあります。あなたのソリューションはまだ最善の方法かもしれませんが、一般的にs ToString()Valueプロパティの代わりに使用する必要はないはずSqlStringです。したがって、状況を確認するだけでいいでしょう。
ソロモンラツキー

明確にするために回答を投稿しましたが、変数をに渡さないため、設定によって問題解決するべきではありRegexOptions.CultureInvariantません。元のコードと新しい動作中のコードの間で変わったのは、からに進んだことです。を使用するように切り替えた場合、同じ固定動作が表示されると思われます。しかし、私はそれをテストとして行うだけです。最善のアプローチは、WindowsまたはSQL ServerのいずれかのLCIDを他方に合わせて変更することです。Options静的変数を削除することもできます。OptionsRegex.IsMatch(sqldata, regex)SqlString.ValueSqlString.ToString()SqlChars
ソロモンラツキー

こんにちは。私の答えを受け入れてくれてありがとう:)。言及するだけで、私はさらなる研究を行い、私が見ているものを理解していれば、OSとSQL Server間で異なるLCIDである根本原因については正しいですが、それは.Valueプロパティに関連していない、または関連するべきではありませんのSqlStringように、明らかに.ToString()メソッドと同じ内部値を返します。私はまだ調査中であり、見つけたもので答えを更新します:)。
ソロモンラッツキー

新しい情報に照らして答えを調整しました。このシナリオを再現することはできません。質問のコードは本当にあなたが使っていた/使っているものですか?それらの間の唯一の本当の違いは、エラーが使用するものと使用RegexOptions.IgnoreCaseしないものです。同様の環境をセットアップしました:LCID 1033を使用するWindows(8.0)、SQL Server DBは1039のLCIDを持ち、投稿したものと同じRegExを使用し、GUIDで満たさCOUNT(*)れたVARCHARフィールド'[0-3â].*'で、テーブルでのパターンを使用します1000万行。2014年ではなくSQL Server 2012ですが、それは問題ではないと思います。
ソロモンラッツキー

1
すべての答えをありがとう。質問のコードは、私が使用していたものです。私は本当に複雑な正規表現を持っていましたが、非常に単純な正規表現を使用してこれをクラッシュさせることができました。RegexOptions.CultureInvariant設定を変更すると、動作が停止しました
-SpörriSep
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.