Operador do dia – Spool
Pessoal como podemos ver o operador de hoje é o Spool, e ele tem várias funções dentro dos planos de execução. O conceito pode ser utilizado em várias tarefas.
Basicamente falando, ele pega um resultado intermediário e armazena este resultado no TempDB. Este processo é feito sempre que o resultado armazenado é muito complexo para ser calculado, para estes casos, ele faz o calculo apenas uma vez, e depois armazena o resultado para futuras consultas.
Os operadores de Spool sempre são utilizados em conjunto com outros operadores. Como eles armazenam um valor, eles precisam receber este valor para ser armazenado. E este valor futuramente pode ser lido por um select. Por exemplo, o spool pode ser utilizado junto com um clustered índex scan, onde ele armazena as linhas lidas pelo scan.
Uma simples representação gráfica do que eu disse seria um plano mais ou menos assim.
Figura 1
No exemplo da figura 1 a ordem seria: Clustered Index Scan passaria os dados para o Spool e o Select lê os dados diretamente do Spool.
Vamos ver cada tipo de spool individualmente começando com o Eager Spool .
Bom, a palavra Eager significa ansioso, ou ávido em inglês. O papel do Eager Spool é pegar todas as linhas recebidas por um outro operador e armazenar estas linhas no tempdb.
Caso o operador que passou os dados para o Spool não faz nenhum calculo(por exemplo, um nested loop), então o spool pode ser utilizado pelo próximo operador para ler os dados. Mas caso os dados tenham que ser calculados(por exemplo, um stream aggregate) então o Spool terá que chamar o operador novamente para calcular os dados e retornar para ele.
O operador é “Eager” porque assim que o operador anterior a ele(operador de select no exemplo da figura 1), requer as suas linhas, ele vai no operador seguinte a ele(operador de clustered índex scan no exemplo da figura 1) e já pega todas as linhas do clustered índex scan, e não uma linha por vez(conforme requisição).
Com base nisso, podemos dizer que o Eager Spool é um operador do tipo blocking. Opa eu ainda não falei sobre a diferença entre operadores blocking e nonblocking?
Ok vamos abrir um enorme parênteses aqui.
(
Existem duas categorias de operadores: os operadores “nonblocking” e os operadores “blocking” ou “stop-and-go”:
Os operadores nonblocking são aqueles que lêem as linhas do input e produzem o output ao mesmo tempo. No método conhecido por GetRow(), conforme a leitura das linhas vão acontecendo, o operador executa sua tarefa e já retorna o output para o próximo operador fazer seu trabalho. O operador de Nested Loop é um bom exemplo desse comportamento. Assim que a primeira linha é recebida (GetRow()) o SQL faz o Join com a tabela do outer, e caso o relacionamento seja verdadeiro a linha é retornada no output. Este processo se repete até o fim da leitura na tabela do Join;
Já os operadores “blocking” necessitam primeiro ler todas as linhas (normalmente no método Open()) do input para depois retorná-las para o output. Um exemplo clássico de operadores blocking é o Sort, que necessita primeiro ler todas as linhas do input para fazer a ordenação e, por fim, retornar as linhas ordenadas.
)
Pessoal comecei a escrever os códigos para simular os “Spool”s, e percebi que isso seria um pouco mais difícil do que eu imaginava. Criar as tabelas, e os selects, forçando determinada situação é bem complicado e requer uma boa imaginação.
Ao invés de esperar eu terminar os scripts para colocar o post, vou postar somente isso, e quando eu terminar os scripts, continuo a escrita, já vi que esse vai ser um operador que vai dar bastante o que falar, ou melhor, escrever.
Portanto, Continua….
Abraço.
Muito boa essas explicações, muito interessante
Até hoje não sabia a diferença de operadores blocking e non-blocking. Muito interessante o artigo, Fabiano.
Explicações bastantes interessantes!