No meu escritório, temos uma consulta bastante feia, mas funciona muito bem na produção e no ambiente de desenvolvimento (20 e 4 segundos, respectivamente). No entanto, em nosso ambiente de teste, leva mais de quatro horas. O SQL2005 (+ patches mais recentes) está em execução na produção e desenvolvimento. SQL2008R2 está sendo executado no teste.
Dei uma olhada no Plano de Consulta e mostra que o SQL2008R2 está usando o TempDB, por meio de um Spool de Tabela (spool lento) para armazenar as linhas retornadas do servidor vinculado. A próxima etapa é mostrar Loops aninhados (anti-junção esquerda) como consumindo 96,3% da consulta. A linha entre os dois operadores é de 5.398 MB!
O plano de consulta para o SQL 2005 mostra nenhum uso de tempdb e nenhum uso de uma junção anti-esquerda esquerda.
Abaixo está o código higienizado e a execução planeja o plano de 2005 em cima, o 2008R2 em baixo.
O que está causando a drástica desaceleração e mudança? Eu esperava ver um plano de execução diferente, para que não me incomodasse. A dramática desaceleração no tempo de consulta é o que me preocupa.
Preciso olhar o hardware subjacente, já que a versão 2008R2 está usando o tempdb, preciso dar uma olhada em como otimizar o uso disso?
Existe uma maneira melhor de escrever a consulta?
Obrigado pela ajuda.
INSERT INTO Table1_GroupLock (iGroupID, dLockedDate)
SELECT
Table1.iGroupID,
GETDATE()
FROM Table1
WHERE
NOT EXISTS (
SELECT 1
FROM LinkedServer.Database.Table2 Alias2
WHERE
(
Alias2.FirstName + Alias2.LastName = dbo.fnRemoveNonLetter(Table1.FullName)
AND NOT dbo.fnRemoveNonLetter(Table1.FullName) IS NULL
AND NOT Alias2.FirstName IS NULL
AND NOT Alias2.LastName IS NULL
) OR (
Alias2.FamilyName = dbo.fnRemoveNonLetter(Table1.FamilyName)
AND Alias2.Child1Name = dbo.fnRemoveNonLetter(Table1.Child1Name)
AND NOT dbo.fnRemoveNonLetter(Table1.FamilyName) IS NULL
AND NOT dbo.fnRemoveNonLetter(Table1.Child1Name) IS NULL
AND NOT Alias2.Familyname IS NULL
AND NOT Alias2.Child1Name IS NULL
) OR (
Alias2.StepFamilyName = dbo.fnRemoveNonLetter(Table1.StepFamilyName)
AND Alias2.StepFamilyNameChild1 = dbo.fnRemoveNonLetter(Table1.StepFamilyNameChild2)
AND NOT Alias2.StepFamilyName IS NULL
AND NOT Alias2.StepFamilyNameChild1 IS NULL
AND NOT dbo.fnRemoveNonLetter(Table1.StepFamilyName) IS NULL
AND NOT dbo.fnRemoveNonLetter(Table1.StepFamilyNameChild2) IS NULL
)
) AND NOT EXISTS (
SELECT 1
FROM Table3
INNER JOIN Table4
ON Table4.FirstNameType = Table3.FirstNameType
INNER JOIN table5
ON table5.LastNameType = Table3.LastNameType
WHERE
Table3.iGroupID = Table1.iGroupID
AND Table3.bIsClosed = 0
AND Table4.sNameTypeConstant = 'new_lastname'
AND table5.sFirstNameConstant = 'new_firstname'
)
:: EDIT :: Executou a consulta de uma instância diferente do SQL2005, praticamente o mesmo plano de execução que o "bom". Ainda não tenho certeza de como as duas versões de 2005 estão executando melhor no servidor vinculado 2008R2 do que nas instâncias 2008R2 e nas instâncias 2008R2.
Embora eu não negue que o código possa usar algum trabalho, se esse fosse o problema, eu não veria os mesmos planos executivos em todos os meus testes? Independentemente da versão do SQL?
:: EDIT :: Eu apliquei o SP1 e o CU3 em ambas as instâncias 2008R2, ainda sem dados. Eu configurei especificamente a colocação no servidor vinculado, sem dados. Eu configurei especificamente as permissões do meu usuário para ser sysadmin nas duas instâncias, sem dados. Lembrei-me também das questões internas e da solução de problemas do meu sql server 2008; veremos se consigo rastrear isso de alguma maneira.
Obrigado a todos pela ajuda e pelas dicas.
:: EDIT :: Fiz várias alterações de permissão no servidor vinculado. Eu usei logons SQL, logons de domínio, personifiquei usuários, usei a opção "ser criado usando este contexto de segurança". Eu criei usuários nos dois lados do servidor vinculado que possuem direitos sysadmin no servidor. Estou sem idéias.
Eu ainda gostaria de saber por que o SQL2005 está executando a consulta tão dramaticamente diferente do SQL2008R2. Se a consulta estivesse ruim, eu veria o tempo de execução de 4 horas no SQL2005 e SQL2008R2.