ボトムライン:WHERE
句に条件を追加し、クエリを4つの個別のクエリに分割します。各フィールドに1つを指定することで、SQLサーバーは並列プランを提供し、WHERE
句に余分なテストを行わずにクエリを4倍速く実行できました。テストなしでクエリを4つに分割しても、それはできませんでした。クエリを分割せずにテストを追加することもしませんでした。テストの最適化により、合計実行時間が3分に短縮されました(元の3時間から)。
元のUDFは1,174,731行を処理するのに3時間16分かかり、1.216 GBのnvarcharデータをテストしました。Martin Smithの回答でCLRを使用すると、実行計画はまだ並行しておらず、タスクには3時間5分かかりました。
そのWHERE
基準を読んだことは、UPDATE
並列にに、次のことを行いました。CLRモジュールに関数を追加して、フィールドが正規表現に一致するかどうかを確認しました。
[SqlFunction(IsDeterministic = true,
IsPrecise = true,
DataAccess = DataAccessKind.None,
SystemDataAccess = SystemDataAccessKind.None)]
public static SqlBoolean CanReplaceMultiWord(SqlString inputString, SqlXml replacementSpec)
{
string s = replacementSpec.Value;
ReplaceSpecification rs;
if (!cachedSpecs.TryGetValue(s, out rs))
{
var doc = new XmlDocument();
doc.LoadXml(s);
rs = new ReplaceSpecification(doc);
cachedSpecs[s] = rs;
}
return rs.IsMatch(inputString.ToString());
}
そして、ではinternal class ReplaceSpecification
、正規表現に対してテストを実行するコードを追加しました
internal bool IsMatch(string inputString)
{
if (Regex == null)
return false;
return Regex.IsMatch(inputString);
}
すべてのフィールドが単一のステートメントでテストされる場合、SQLサーバーは作業を並列化しません
UPDATE dbo.DeidentifiedTest
SET IndexedXml = dbo.ReplaceMultiWord(IndexedXml, @X),
DE461 = dbo.ReplaceMultiWord(DE461, @X),
DE87 = dbo.ReplaceMultiWord(DE87, @X),
DE15 = dbo.ReplaceMultiWord(DE15, @X)
WHERE InProcess = 1
AND (dbo.CanReplaceMultiWord(IndexedXml, @X) = 1
OR DE15 = dbo.ReplaceMultiWord(DE15, @X)
OR dbo.CanReplaceMultiWord(DE87, @X) = 1
OR dbo.CanReplaceMultiWord(DE15, @X) = 1);
4時間30分以上実行し、まだ実行中の時間。実行計画:
ただし、フィールドが個別のステートメントに分割されている場合、並列作業計画が使用され、CPU使用率はシリアル計画の12%から並列計画(8コア)の100%になります。
UPDATE dbo.DeidentifiedTest
SET IndexedXml = dbo.ReplaceMultiWord(IndexedXml, @X)
WHERE InProcess = 1
AND dbo.CanReplaceMultiWord(IndexedXml, @X) = 1;
UPDATE dbo.DeidentifiedTest
SET DE461 = dbo.ReplaceMultiWord(DE461, @X)
WHERE InProcess = 1
AND dbo.CanReplaceMultiWord(DE461, @X) = 1;
UPDATE dbo.DeidentifiedTest
SET DE87 = dbo.ReplaceMultiWord(DE87, @X)
WHERE InProcess = 1
AND dbo.CanReplaceMultiWord(DE87, @X) = 1;
UPDATE dbo.DeidentifiedTest
SET DE15 = dbo.ReplaceMultiWord(DE15, @X)
WHERE InProcess = 1
AND dbo.CanReplaceMultiWord(DE15, @X) = 1;
46分を実行する時間。行統計では、レコードの約0.5%に少なくとも1つの正規表現の一致があったことが示されました。実行計画:
さて、時間通りの主なドラッグはWHERE
条項でした。次に、で正規表現テストを置き換えましたWHERE
句の CLRとして実装されたAho-Corasickアルゴリズムに。これにより、合計時間が3分6秒に短縮されました。
これには、次の変更が必要でした。Aho-Corasickアルゴリズムのアセンブリと関数を読み込みます。WHERE
句を変更します
WHERE InProcess = 1 AND dbo.ContainsWordsByObject(ISNULL(FieldBeingTestedGoesHere,'x'), @ac) = 1;
そして、最初の前に以下を追加します UPDATE
DECLARE @ac NVARCHAR(32);
SET @ac = dbo.CreateAhoCorasick(
(SELECT NAMES FROM dbo.NamesMultiWord FOR XML RAW, root('root')),
'en-us:i'
);
SELECT @var = REPLACE ... ORDER BY
あなたが期待するような構成は、仕事に保証するものではありません。接続項目の例(Microsoftからの応答を参照)。そのため、SQLCLRに切り替えると、常に正しい結果が得られるという利点があります。