Tengo una consulta que demora aproximadamente 3 horas en ejecutarse en nuestro servidor, y no aprovecha el procesamiento paralelo. (alrededor de 1,15 millones de registros dbo.Deidentified, 300 registros dbo.NamesMultiWord). El servidor tiene acceso a 8 núcleos.
UPDATE dbo.Deidentified
WITH (TABLOCK)
SET IndexedXml = dbo.ReplaceMultiWord(IndexedXml),
DE461 = dbo.ReplaceMultiWord(DE461),
DE87 = dbo.ReplaceMultiWord(DE87),
DE15 = dbo.ReplaceMultiWord(DE15)
WHERE InProcess = 1;
y ReplaceMultiwordes un procedimiento definido como:
SELECT @body = REPLACE(@body,Names,Replacement)
FROM dbo.NamesMultiWord
ORDER BY [WordLength] DESC
RETURN @body --NVARCHAR(MAX)
¿Es el llamado a ReplaceMultiwordprevenir la formación de un plan paralelo? ¿Hay alguna manera de reescribir esto para permitir el paralelismo?
ReplaceMultiword se ejecuta en orden descendente porque algunos de los reemplazos son versiones cortas de otros, y quiero que la coincidencia más larga tenga éxito.
Por ejemplo, puede haber 'George Washington University' y otra de 'Washington University'. Si el partido 'Washington University' fuera el primero, entonces 'George' se quedaría atrás.
Técnicamente puedo usar CLR, simplemente no estoy familiarizado con cómo hacerlo.


SELECT @var = REPLACE ... ORDER BYse 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.Respuestas:
El UDF está evitando el paralelismo. También está causando ese carrete.
Puede usar CLR y una expresión regular compilada para hacer su búsqueda y reemplazar. No bloquea el paralelismo mientras los atributos requeridos estén presentes y probablemente sea significativamente más rápido que realizar 300
REPLACEoperaciones TSQL por llamada a la función.El código de ejemplo está abajo.
Esto depende de la existencia de un CLR UDF como se muestra a continuación (esto
DataAccessKind.Nonedebería significar que el carrete desaparece y que está ahí para la protección de Halloween y no es necesario ya que esto no accede a la tabla de destino).fuente
wherecláusula usando una prueba de coincidencia con la expresión regular, ya que la mayoría de las escrituras son innecesarias: la densidad de 'hits' debería ser baja, pero mis habilidades de C # (soy un chico de C ++) no lo hicieron llévame allí. Estaba pensando en las líneas de un procedimientopublic static SqlBoolean CanReplaceMultiWord(SqlString inputString, SqlXml replacementSpec)que regresaríareturn Regex.IsMatch(inputString.ToString());pero recibo errores en esa declaración de retorno, como `System.Text.RegularExpressions.Regex es un tipo pero se usa como una variable.En pocas palabras : al agregar criterios a la
WHEREclá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 laWHEREclá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
WHEREcriterio podría ayudar a empujar a unUPDATEparalelo, 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:y, en
internal class ReplaceSpecification, agregué el código para ejecutar la prueba contra la expresión regularSi todos los campos se prueban en una sola declaración, el servidor SQL no paraleliza el trabajo
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).
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
WHEREcláusula. Luego reemplacé la prueba de expresiones regulares en laWHEREclá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
WHEREcláusula aY agregue lo siguiente antes del primero
UPDATEfuente