En pocas palabras : al agregar criterios a la WHERE
cláusula y dividir la consulta en cuatro consultas separadas, una para cada campo permitió que el servidor SQL proporcionara un plan paralelo e hizo que la consulta se ejecutara 4 veces más rápido que antes sin la prueba adicional en la WHERE
cláusula. Dividir las consultas en cuatro sin la prueba no hizo eso. Tampoco agregar la prueba sin dividir las consultas. La optimización de la prueba redujo el tiempo total de ejecución a 3 minutos (desde las 3 horas originales).
Mi UDF original tardó 3 horas y 16 minutos en procesar 1.174.731 filas, con 1.216 GB de datos de nvarchar probados. Utilizando el CLR proporcionado por Martin Smith en su respuesta, el plan de ejecución aún no era paralelo y la tarea tomó 3 horas y 5 minutos.
Después de leer ese WHERE
criterio podría ayudar a empujar a un UPDATE
paralelo, hice lo siguiente. Agregué una función al módulo CLR para ver si el campo tenía una coincidencia con la expresión regular:
[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());
}
y, en internal class ReplaceSpecification
, agregué el código para ejecutar la prueba contra la expresión regular
internal bool IsMatch(string inputString)
{
if (Regex == null)
return false;
return Regex.IsMatch(inputString);
}
Si todos los campos se prueban en una sola declaración, el servidor SQL no paraleliza el trabajo
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);
Tiempo para ejecutar más de 4 1/2 horas y aún en ejecución. Plan de ejecución:
Sin embargo, si los campos se separan en declaraciones separadas, se usa un plan de trabajo paralelo y mi uso de CPU pasa del 12% con los planes en serie al 100% con los planes paralelos (8 núcleos).
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;
Tiempo para ejecutar 46 minutos. Las estadísticas de fila mostraron que aproximadamente el 0.5% de los registros tenían al menos una coincidencia de expresiones regulares. Plan de ejecución:
Ahora, el lastre principal en el tiempo era la WHERE
cláusula. Luego reemplacé la prueba de expresiones regulares en la WHERE
cláusula con el algoritmo Aho-Corasick implementado como un CLR. Esto redujo el tiempo total a 3 minutos y 6 segundos.
Esto requirió los siguientes cambios. Cargue el ensamblaje y las funciones para el algoritmo Aho-Corasick. Cambiar la WHERE
cláusula a
WHERE InProcess = 1 AND dbo.ContainsWordsByObject(ISNULL(FieldBeingTestedGoesHere,'x'), @ac) = 1;
Y agregue lo siguiente antes del primero 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
se garantiza que la construcción funcione como espera. Ejemplo de elemento de conexión (consulte la respuesta de Microsoft). Por lo tanto, cambiar a SQLCLR tiene la ventaja adicional de garantizar resultados correctos, lo que siempre es bueno.