Máquinas idênticas (?) Do SQL Server 2005; consulta leva 2seg em um, 15min no outro

12

O ambiente:

Temos duas máquinas Windows Server 2003 R2 de 32 bits executando o SQL Server 2005. As configurações de hardware são servidores idênticos com CPU Xeon 5160, 4 GB de RAM e 13 GB de RAID0. Os sinalizadores AWE e / 3GB não estão ativados.

Os servidores foram configurados lado a lado usando uma lista de verificação de instalação predefinida e TODOS os softwares instalados são os mesmos nas duas máquinas.

Cada configuração de instalação do servidor SQL e nível de patch que sabemos verificar são idênticos. Uma diferença é que o TEMPDB tem 400 MB na máquina rápida e 1,2 GB na máquina lenta. No entanto, em ambos os casos, não vemos nenhuma alocação de TEMPDB ocorrendo.

O problema:

Há um procedimento armazenado que é executado em 2 segundos em um, mas 15 minutos no outro. Durante os 15 minutos adicionais, há pouca ou nenhuma atividade no disco, nenhum uso de memória é alterado, mas um núcleo da CPU é fixado em 100% o tempo todo.

Esse comportamento persiste mesmo quando o backup dos bancos de dados é feito de um e restaurado no outro.

Como é um procedimento armazenado, o monitor de atividade e o criador de perfil não nos mostram detalhes sobre onde está ocorrendo essa atividade de alta CPU no procedimento armazenado.

A questão:

O que mais devemos olhar?

Acompanhamento:

A lentidão ocorre nas instruções FETCH NEXT para a seguinte definição de cursor:

DECLARE C CURSOR FOR
    SELECT X, Y
    FROM dbo.A
    WHERE X NOT IN (SELECT X FROM dbo.B)
    AND Z <=0
...
<snip>
...
FETCH NEXT FROM C INTO @X, @Y
FETCH NEXT FROM C INTO @X, @Y
...

Cada uma das instruções FETCH - em uma tabela contendo apenas cerca de 1000 linhas - requer cerca de 7,25 minutos. (Não, eu não sei por que ele faz dois seguidos, preciso perguntar aos desenvolvedores, mas ele é executado corretamente nos dois servidores).

Desconfio um pouco desse "NOT IN (SELECT ...)", pois parece que o Virtual Reads é realmente alto.

Ryandenki
fonte
Como podem os registros no dbo.B e o dbo.BX ser indexado?
Mark-Storey-Smith #
1
Estou curioso para saber se haveria uma diferença de desempenho se você seguisse com isso: selecione dbo.ax, dbo.ay em dbo.a junção externa esquerda dbo.b em dbo.ax = dbo.bx em que dbo.bx é nulo e z <= 0
DForck42 6/06
Mais um pensamento para jogar na mistura. Você tem certeza de que a desaceleração ocorre devido à busca do cursor? Você está determinando isso no plano de execução (que tem tudo a ver com estimativas) ou com um rastreamento de perfil?
Mark-Storey-Smith
É de um rastreamento de perfil.
Ryandenki 12/12
Os planos de execução são os mesmos? É possível que um deles esteja usando um plano de execução incorreto.
Zane

Respostas:

7

Usando uma metodologia de solução de problemas de desempenho como Esperas e Filas, identifique o motivo do alto consumo de CPU, a ação apropriada poderá ser recomendada assim que o gargalo for identificado.

Remus Rusanu
fonte
6

O SQL Server está escolhendo um plano diferente na outra caixa.

A restauração normalmente remove problemas com base em estatísticas, portanto, observei as diferenças do servidor.

Algumas verificações grosseiras primeiro. Não assuma: verifique

  • Verifique se as configurações do SQL Server são as mesmas em sys.configuration, por exemplo, grau máximo ou paralelismo
  • Execute USEROPTIONS do DBCC para verificar se alguma configuração ANSI é diferente no tempo de execução (as configurações ANS podem afetar o plano escolhido)
  • Verifique os logs do Windows e do SQL Server para ver se há algum problema

Então pule no fundo do poço, conforme a resposta de Remus.

gbn
fonte
Obrigado pelas dicas. As configurações do sys. e as USEROPTIONS do DBCC são idênticas entre as duas máquinas. Nenhum erro ou aviso em nenhum registro do servidor Windows ou SQL.
1
E eles também executam o layout de banco de dados idêntico? Nenhum plano de administração otimizando (reconstrução do índice etc.), os bancos de dados têm as mesmas estatísticas para objetos relevantes e o mesmo layout de disco? Mesmo nível de patch?
TomTom
Sim, mesmo disco, layout do banco de dados e nível de patch. De fato, o banco de dados na máquina rápida é um backup restaurado da máquina lenta. E não há planos de administração que variam, tanto quanto eu posso ver.
Ryandenki 6/10
6

Se todas as outras coisas forem iguais, é provável (conforme a resposta de @ gbn) que um plano de execução diferente esteja sendo gerado em cada servidor. Como um exercício acadêmico, seria interessante ver os dois planos, então pegue-os no cache do plano em cada servidor e adicione-os à sua pergunta, se possível. Podemos então identificar as diferenças nos planos que estão causando uma variação tão grande no desempenho.

Para uma solução rápida, consulte a dica USE PLAN . Isso torna possível anexar o bom plano do servidor rápido ao procedimento armazenado no servidor lento.

Edit: Após atualização re: cursor

Outra variação em sua consulta para tentar não ver mencionada em outras respostas:

DECLARE C CURSOR FOR
    SELECT X, Y
    FROM dbo.A
    WHERE NOT EXISTS (SELECT 1 FROM dbo.B WHERE dbo.B.X = dbo.A.X)
    AND Z <=0
...
<snip>
...
FETCH NEXT FROM C INTO @X, @Y
FETCH NEXT FROM C INTO @X, @Y
Mark Storey-Smith
fonte
Este é um bom conselho, estamos verificando os planos de consulta. Na verdade, a desaceleração no procedimento armazenado parece estar vinculada a um cursor. Veja editar.
Ryandenki 6/10
4

Humor me, e tente substituir:

DECLARE C CURSOR FOR
SELECT X, Y
FROM dbo.A
WHERE X NOT IN (SELECT X FROM dbo.B)
AND Z <=0

com isso:

DECLARE C CURSOR FOR
SELECT 
    X, 
    Y
FROM dbo.A

    LEFT OUTER JOIN dbo.B
        ON dbo.A.X = dbo.b.X

WHERE dbo.B.X IS NULL
AND Z <=0

Acho que isso não deve se manifestar como um problema de desempenho na parte FETCH NEXT FROM do seu código, mas ainda não tomei minha injeção de cafeína. Experimente minha sugestão e me avise.

Espero que isto ajude,

Matt

Matt M
fonte
4

Verifique seus índices e atualize todas as suas estatísticas. Eu tive um problema muito simples e acabou que as estatísticas em uma máquina eram instáveis.

DForck42
fonte
1

Eu experimentei esse mesmo comportamento duas vezes e vou lhe dizer o que o corrigiu toda vez:

1.) Adicionei a dica WITH RECOMPILE ao procedimento armazenado porque o plano em cache era terrível.

2.) Alterei o procedimento armazenado para usar tabelas temporárias em vez de variáveis ​​de tabela.

Espero que qualquer uma dessas ajuda. Boa sorte.

Jon
fonte