Eu tive esse problema há muito tempo, encontrei uma solução alternativa que me convinha e esqueci.
Mas agora há essa pergunta no SO, então estou disposto a trazer esse problema à tona.
Há uma visão que une poucas tabelas de maneira muito direta (pedidos + linhas de pedidos).
Quando consultada sem uma where
cláusula, a exibição retorna vários milhões de linhas.
No entanto, ninguém nunca chama assim. A consulta usual é
select * from that_nasty_view where order_number = 123456;
Isso retorna cerca de 10 registros de 5m.
Uma coisa importante: a visualização contém uma função da janela rank()
, que é particionada exatamente pelo campo usando o qual a visualização é sempre consultada:
rank() over (partition by order_number order by detail_line_number)
Agora, se essa visualização for consultada com parâmetros literais na string de consulta, exatamente como mostrado acima, ela retornará as linhas instantaneamente. O plano de execução está bom:
- Procura de índice em ambas as tabelas usando os índices on
order_number
(retorna 10 linhas). - Cálculo de janelas sobre o pequeno resultado retornado.
- Selecionando.
No entanto, quando a exibição é chamada de maneira parametrizada, as coisas ficam desagradáveis:
Index scan
em todas as tabelas ignorando índices. Retorna 5m de linhas.- Enorme junção.
- Cálculo de janelas sobre todos os
partition
s (cerca de 500k janelas). Filter
tirar 10 linhas de 5m.- Selecione
Isso acontece em todos os casos quando parâmetros estão envolvidos. Pode ser SSMS:
declare @order_number int = 123456;
select * from that_nasty_view where order_number = @order_number;
Pode ser um cliente ODBC, como o Excel:
select * from that_nasty_view where order_number = ?
Ou pode ser qualquer outro cliente que use parâmetros e não concatenação sql.
Se a função da janela for removida da exibição, ela será executada perfeitamente rapidamente, independentemente de ser ou não consultada com parâmetros.
Minha solução alternativa foi remover a função incorreta e reaplicá-la posteriormente.
Mas o que dá? É realmente um bug na maneira como o SQL Server 2008 lida com as funções da janela?
order_number
não é uma chave primária. É int not null
com índice não clusterizado nas duas tabelas.
OPTION (RECOMPILE)
ajuda?