Pergunta

Ao desenvolver uma nova consulta no trabalho eu escrevi e perfilado-lo no SQL Query Analyzer. A consulta estava realizando realmente bom, sem quaisquer varreduras de tabela, mas quando eu encapsulado dentro de um procedimento armazenado o desempenho foi horrível. Quando olhei para o plano de execução Eu podia ver que o SQL Server pegou um plano diferente que usou uma varredura da tabela em vez de uma busca de índice em TableB (eu fui forçado a ofuscar os nomes de tabelas e colunas um pouco, mas nenhum dos lógica de consulta mudou).

Aqui está a consulta

SELECT     
    DATEADD(dd, 0, DATEDIFF(dd, 0, TableA.Created)) AS Day, 
    DATEPART(hh, TableA.Created) AS [Hour], 
    SUM(TableB.Quantity) AS Quantity, 
    SUM(TableB.Amount) AS Amount
FROM
    TableA
    INNER JOIN TableB ON TableA.BID = TableB.ID
WHERE     
    (TableA.ShopId = @ShopId)
GROUP BY 
    DATEADD(dd, 0, DATEDIFF(dd, 0, TableA.Created)), 
    DATEPART(hh, TableA.Created)
ORDER BY 
    DATEPART(hh, TableA.Created)

Quando eu executar a consulta "raw" Eu recebo as seguintes estatísticas de rastreamento

Event Class         Duration  CPU  Reads Writes
SQL:StmtCompleted   75        41      7      0

E quando eu executar a consulta como um proc armazenados usando o seguinte comando

DECLARE @ShopId int
SELECT @ShopId = 1
EXEC spStats_GetSalesStatsByHour @ShopId

Eu recebo as seguintes estatísticas de rastreamento

Event Class         Duration  CPU  Reads Writes
SQL:StmtCompleted   222       10     48      0

Eu também obter o mesmo resultado se eu armazenar a consulta em um nvarchar e executá-lo usando sp_executesql assim (ele executa como o sproc)

DECLARE @SQL nvarchar(2000)
SET @SQL = 'SELECT DATEADD(dd, ...'
exec sp_executesql @SQL

O procedimento armazenado não contém qualquer coisa, exceto para a instrução SELECT acima. O que faria com que o SQL Server para escolher um plano de execução inferior só porque a instrução é executada como um procedimento armazenado?

Nós estamos correndo atualmente no SQL Server 2000

Foi útil?

Solução

Isso geralmente tem algo a ver com o parâmetro sniffing. Ele pode ser muito frustrante para lidar com eles. Às vezes pode ser resolvido por recompilar o procedimento armazenado, e às vezes você pode até usar uma variável duplicado dentro do procedimento armazenado como esta:

alter procedure p_myproc (@p1 int) as
declare @p1_copy int;
set @p1_copy = @p1;

E, em seguida, usar @ p1_copy na consulta. Parece ridículo, mas ele funciona.

Verifique minha pergunta recente sobre o mesmo tema:

Por que o SqlServer otimizador ficar tão confundido com parâmetros?

Outras dicas

Sim - Eu já tinha visto isso em banco de dados Oracle 11g bem - mesma consulta correu rápido em 2 nós de servidor db no SQL pronto, mas quando chamado de pacote que literalmente desligou

teve que limpar a piscina comum para obter um comportamento idêntico:. Motivo algum trabalho / script estava correndo que tinha cópia mais antiga trancada na biblioteca cache / memória em um nó com plano de execução inferior

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top