결론 : WHERE
절에 기준을 추가 하고 쿼리를 4 개의 개별 쿼리로 나누면 각 필드마다 하나씩 SQL Server가 병렬 계획을 제공하고 WHERE
절 에서 추가 테스트없이 4 배 빠르게 쿼리를 실행할 수있었습니다 . 테스트없이 쿼리를 4로 나누면 그렇게되지 않았습니다. 쿼리를 나누지 않고 테스트를 추가하지 않았습니다. 테스트를 최적화하면 총 실행 시간이 원래 3 시간에서 3 분으로 줄었습니다.
내 원래 UDF는 1,174,731 개의 행을 처리하는 데 3 시간 16 분이 걸렸으며 1.216GB의 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 Server가 작업을 병렬화하지 않습니다.
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 1/2 시간 이상 실행되고 여전히 실행되는 시간. 실행 계획 :
그러나 필드가 별도의 문으로 분리되면 병렬 작업 계획이 사용되고 내 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 %가 최소한 하나의 정규식 일치를 나타 냈습니다. 실행 계획 :
이제 시간의 주요 드래그는 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로 전환하면 올바른 결과를 보장 할 수 있다는 이점이 있습니다.