Comparação de desempenho entre o uso das funções Join e Window para obter valores de lead e lag

11

Eu tenho uma tabela com linhas 20m, e cada linha tem 3 colunas: time, id, e value. Para cada ide time, existe um valuepara o status. Quero saber os valores de lead e lag de um determinado timepara um específico id.

Eu usei dois métodos para conseguir isso. Um método está usando junção e outro método está usando as funções da janela lead / lag com o índice clusterizado em timee id.

Eu comparei o desempenho desses dois métodos pelo tempo de execução. O método de junção leva 16,3 segundos e o método da função de janela leva 20 segundos, não incluindo o tempo para criar o índice. Isso me surpreendeu porque a função window parece ser avançada enquanto os métodos de junção são força bruta.

Aqui está o código para os dois métodos:

Criar índice

create clustered index id_time
 on tab1 (id,time)

Método de junção

select a1.id,a1.time
   a1.value as value, 
   b1.value as value_lag,
   c1.value as value_lead
into tab2
from tab1 a1
left join tab1 b1
on a1.id = b1.id
and a1.time-1= b1.time
left join tab1 c1
on a1.id = c1.id
and a1.time+1 = c1.time

Estatísticas de E / S geradas usando SET STATISTICS TIME, IO ON:

Estatísticas para o método Join

Aqui está o plano de execução para o método de junção

Método da função de janela

select id, time, value, 
   lag(value,1) over(partition by id order by id,time) as value_lag,
   lead(value,1) over(partition by id order by id,time) as value_lead
into tab2
from tab1

(Solicitar apenas timeeconomiza 0,5 segundos.)

Aqui está o plano de execução para o método da função Window

Estatísticas de IO

[Estatísticas para o método da função Window 4]


Eu verifiquei os dados sample_orig_month_1999e parece que os dados brutos estão bem ordenados por ide time. É este o motivo da diferença de desempenho?

Parece que o método de junção tem leituras mais lógicas que o método da função de janela, enquanto o tempo de execução do primeiro é realmente menor. É porque o primeiro tem um paralelismo melhor?

Eu gosto do método de função de janela por causa do código conciso, existe alguma maneira de acelerá-lo para esse problema específico?

Estou usando o SQL Server 2016 no Windows 10 de 64 bits.

Jason
fonte

Respostas:

11

O desempenho relativamente baixo no modo de linha das funções LEADe da LAGjanela em comparação com as junções automáticas não é novidade. Por exemplo, Michael Zilberstein escreveu sobre isso no SQLblog.com em 2012. Há um pouco de sobrecarga nos operadores de planos (repetidos) de segmento, projeto de sequência, spool da janela e agregado de fluxo:

Seção de plano

No SQL Server 2016, você tem uma nova opção, que é habilitar o processamento em modo de lote para as agregações de janelas. Isso requer algum tipo de índice columnstore na tabela, mesmo que esteja vazio. Atualmente, a presença de um índice columnstore é necessária para o otimizador considerar planos de modo em lote. Em particular, ele habilita o operador de modo em lote muito mais eficiente do Window Aggregate.

Para testar isso no seu caso, crie um índice columnstore não clusterizado vazio:

 -- Empty CS index
CREATE NONCLUSTERED COLUMNSTORE INDEX dummy 
ON dbo.tab1 (id, [time], [value]) 
WHERE id < 0 AND id > 0;

A pergunta:

SELECT
    T1.id,
    T1.[time],
    T1.[value],
    value_lag = 
        LAG(T1.[value]) OVER (
            PARTITION BY T1.id
            ORDER BY T1.[time]),
    value_lead =
        LEAD(T1.[value]) OVER (
            PARTITION BY T1.id
            ORDER BY T1.[time])
FROM dbo.tab1 AS T1;

Agora deve fornecer um plano de execução como:

Plano de armazenamento de linhas no modo de lote

... que pode muito bem executar muito mais rápido.

Pode ser necessário usar uma OPTION (MAXDOP 1)ou outra dica para obter a mesma forma de plano ao armazenar os resultados em uma nova tabela. A versão paralela do plano requer uma classificação em modo de lote (ou possivelmente duas), que pode ser um pouco mais lenta. Depende bastante do seu hardware.

Para saber mais sobre o operador Agregado da janela do modo de lote, consulte os seguintes artigos de Itzik Ben-Gan:

Paul White 9
fonte