Tenho uma consulta que leva cerca de 3 horas para ser executada em nosso servidor - e não tira proveito do processamento paralelo. (cerca de 1,15 milhão de registros em dbo.Deidentified
, 300 registros em dbo.NamesMultiWord
). O servidor tem acesso 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;
e ReplaceMultiword
é um procedimento definido como:
SELECT @body = REPLACE(@body,Names,Replacement)
FROM dbo.NamesMultiWord
ORDER BY [WordLength] DESC
RETURN @body --NVARCHAR(MAX)
É o chamado para ReplaceMultiword
impedir a formação de um plano paralelo? Existe uma maneira de reescrever isso para permitir o paralelismo?
ReplaceMultiword
é executado em ordem decrescente, porque algumas das substituições são versões curtas de outras e eu quero que a correspondência mais longa seja bem-sucedida.
Por exemplo, pode haver 'George Washington University' e outro da 'Washington University'. Se a partida da "Universidade de Washington" fosse a primeira, então "George" seria deixado para trás.
Tecnicamente, eu posso usar o CLR, mas não estou familiarizado com isso.
SELECT @var = REPLACE ... ORDER BY
é garantido que a construção funcione conforme o esperado. Exemplo de item de conexão (consulte a resposta da Microsoft). Portanto, a mudança para o SQLCLR tem a vantagem adicional de garantir resultados corretos, o que é sempre bom.Respostas:
A UDF está impedindo o paralelismo. Também está causando esse carretel.
Você pode usar o CLR e um regex compilado para fazer sua pesquisa e substituição. Ele não bloqueia o paralelismo enquanto os atributos necessários estiverem presentes e provavelmente será significativamente mais rápido do que executar 300
REPLACE
operações TSQL por chamada de função.O código de exemplo está abaixo.
Isso depende da existência de um CLR UDF como abaixo (isso
DataAccessKind.None
deve significar que o spool desaparece e também existe para a proteção do Halloween e não é necessário, pois isso não acessa a tabela de destino).fonte
where
cláusula usando um teste para corresponder ao regex, pois a maioria das gravações é desnecessária - a densidade de 'hits' deve ser baixa, mas minhas habilidades em C # (eu sou um cara de C ++) não me leve lá. Eu estava pensando na linha de um procedimentopublic static SqlBoolean CanReplaceMultiWord(SqlString inputString, SqlXml replacementSpec)
que retornaria,return Regex.IsMatch(inputString.ToString());
mas eu recebo erros nessa instrução de retorno, como `System.Text.RegularExpressions.Regex é um tipo, mas é usado como uma variável.Conclusão : adicionar critérios à
WHERE
cláusula e dividir a consulta em quatro consultas separadas, uma para cada campo, permitiu ao SQL Server fornecer um plano paralelo e fez com que a consulta fosse executada 4X o mais rápido que havia, sem o teste extra daWHERE
cláusula. Dividir as consultas em quatro sem o teste não fez isso. Nem foi adicionado o teste sem dividir as consultas. A otimização do teste reduziu o tempo total de execução para 3 minutos (a partir das 3 horas originais).Minha UDF original levou 3 horas e 16 minutos para processar 1.174.731 linhas, com 1.216 GB de dados nvarchar testados. Usando o CLR fornecido por Martin Smith em sua resposta, o plano de execução ainda não era paralelo e a tarefa levou 3 horas e 5 minutos.
Tendo lido esses
WHERE
critérios, poderia ajudar a empurrar umUPDATE
para paralelo, fiz o seguinte. Adicionei uma função ao módulo CLR para ver se o campo correspondia ao regex:e,
internal class ReplaceSpecification
adicionei o código para executar o teste no regexSe todos os campos forem testados em uma única instrução, o SQL Server não paralelizará o trabalho
Tempo para executar mais de 4 horas e meia e ainda em execução. Plano de execução:
No entanto, se os campos forem separados em instruções separadas, um plano de trabalho paralelo será usado, e o uso da minha CPU passará de 12% nos planos seriais para 100% nos planos paralelos (8 núcleos).
Tempo para executar 46 minutos. As estatísticas de linha mostraram que cerca de 0,5% dos registros tinham pelo menos uma correspondência de regex. Plano de execução:
Agora, o principal problema no tempo era a
WHERE
cláusula. Substituí o teste regex naWHERE
cláusula pelo algoritmo Aho-Corasick implementado como um CLR. Isso reduziu o tempo total para 3 minutos e 6 segundos.Isso exigiu as seguintes alterações. Carregue a montagem e as funções do algoritmo Aho-Corasick. Mude a
WHERE
cláusula paraE adicione o seguinte antes do primeiro
UPDATE
fonte