In-Memory OLTP a.k.a Hekaton–Cuidado com as Estatísticas em sua Tabela !

Posted on junho 10, 2014

3


Introdução

As estatísticas são fundamentais em qualquer banco de dados. São com elas que se torna possível criar o melhor plano de execução possível para as consultas, para que isso aconteça, é necessário que as mesmas estejam sempre atualizadas.

Atualização de Estatísticas no SQL Server

As atualizações de estatísticas no SQL Server são realizadas de forma automática. o AUTO-CREATE e o AUTO-UPDATE STATISTICS estão habilitados por padrão no SQL Server e quando é necessário, as mesmas são atualizadas. Existe muito mais conteúdo sobre estatísticas – https://www.simple-talk.com/sql/learn-sql-server/statistics-in-sql-server/, http://blogfabiano.com/?s=estatisticas, mas nesse post iremos falar sobre as estatísticas vinculadas ao recurso In-Memory OLTP do SQL Server 2014 chamado Hekaton.

Atualização de Estatísticas no Hekaton

A criação de tabelas In-Memory é diferente da criação das tabelas On-Disk. A criação da tabela In-Memory é compilada e colocada direto em .DLL assim temos uma velocidade de execução de 2x a 3x, isso porque todos os bancos de dados possuem do que chamamos de INTEPRETER. O interpretador em um SGDB é responsável por traduzir o código que foi escrito e passar para linguagem de máquina. Quando criamos as tabelas In-Memory não precisamos do interpretador porque a mesma é persistida direto em código de máquina. Ganhamos em velocidade de execução que é o principal motivo de ter as tabelas em memória, porém temos que nos alertar em diversos detalhes no qual hã grande impacto caso não tratemos um a um, as estatísticas é uma delas.

Alguns pontos importantes sobre estatísticas In-Memory Tables

Estatísticas não são geradas em tabelas em memória

Não são auto geradas

Não são auto atualizáveis

 

Realizando a consulta abaixo iremos reparar que o Plano de Execução nos alerta alguns detalhes durante sua execução.

SELECT inmem_DAC.NumeroAtendimento,

                                      inmem_DAC.StatusAtendimento,

                                      inmem_VP.Name,

                                      SUM(LineTotal UnitPrice) AS ProductValue,

                                      SUM(inmem_VP.LineTotal) AS LineTotal,

                                      SUM(inmem_VP.UnitPrice) AS UnitPrice,

                                      COUNT(*) AS Quantidade

FROM inmem_DadosAtendimentoClientes  AS inmem_DAC

LEFT OUTER JOIN inmem_VendasProdutos AS inmem_VP

ON inmem_DAC.ID = inmem_VP.SalesOrderID

WHERE StatusAtendimento = ‘Baixado’

GROUP BY inmem_DAC.NumeroAtendimento, inmem_DAC.StatusAtendimento, inmem_VP.Name

HAVING SUM(inmem_VP.UnitPrice) > 2049.0982

ORDER  BY inmem_DAC.NumeroAtendimento DESC

Screen Shot 2014-05-30 at 2.08.00 PM

(Figura 1 – Plano de Execução da Consulta alertando um problema no Hash Match, 25%.)

Reparem que existe um alerta no operador Hash Match do plano de execução, indo mais fundo no problema vemos que…

Screen Shot 2014-05-30 at 2.08.08 PM

(Figura 2 – Detalhes do plano de execução do operador Hash Match.)

 

Notem que o ACTUAL NUMBER OF ROWS = 1.397.041 e o ESTIMATED NUMBER OF ROWS = 261.100  estão completamente errados, isso acontece porque como dito anteriormente as tabelas In-Memory não realizam a atualização de estatísticas. Além de ter estimado o valor errado o que faz com que o plano de execução não seja o mais eficiente o mesmo mostra um WARNING muito custoso. O WARNING mostra “Operator used tempdb to spill data during execution with spill level 1.” Isso quer dizer que a tabela In-Memory está jogando o JOIN no tempDB para realizar a comparação entre as tabelas, assim o custo total da consulta fica extremamente custosa.

Para que não haja esse problema novamente, sempre que for realizado grandes inserções em tabelas In-Memory é necessário que a mesma seja atualizada, com isso se realizarmos a atualização de estatísticas nesse caso iremos reparar que…

Atualizando as Estatísticas…

UPDATE STATISTICS inmem_DadosAtendimentoClientes WITH FULLSCAN, NORECOMPUTE

UPDATE STATISTICS inmem_VendasProdutos WITH FULLSCAN, NORECOMPUTE

Realizando o SELECT novamente…

SELECT inmem_DAC.NumeroAtendimento,

                                      inmem_DAC.StatusAtendimento,

                                      inmem_VP.Name,

                                      SUM(LineTotal UnitPrice) AS ProductValue,

                                      SUM(inmem_VP.LineTotal) AS LineTotal,

                                      SUM(inmem_VP.UnitPrice) AS UnitPrice,

                                      COUNT(*) AS Quantidade

FROM inmem_DadosAtendimentoClientes  AS inmem_DAC

LEFT OUTER JOIN inmem_VendasProdutos AS inmem_VP

ON inmem_DAC.ID = inmem_VP.SalesOrderID

WHERE StatusAtendimento = ‘Baixado’

GROUP BY inmem_DAC.NumeroAtendimento, inmem_DAC.StatusAtendimento, inmem_VP.Name

HAVING SUM(inmem_VP.UnitPrice) > 2049.0982

ORDER  BY inmem_DAC.NumeroAtendimento DESC

Screen Shot 2014-05-30 at 2.14.17 PM

(Figura 3 – Plano de Execução da Consulta com Hash Match, agora com 3%.)

Screen Shot 2014-05-30 at 2.14.31 PM

(Figura 4 – Detalhes do plano de execução do operador Hash Match após atualizado.)

 

OBS – O Operador Hash Match custava 25% e agora está custando somente 3%

 

Agora o ACTUAL NUMBER OF ROWS e o ESTIMATED NUMBER OF ROWS estão equivalente após a atualização de estatísticas até porque o HISTOGRAMA foi atualizado, além disso não foi gerado o WARNING anterior da consulta e o custo do Hash Match agora é de 3%.

Com isso, sempre que a tabelas em memória (In-Memory Tables) sofrerem atualizações, realize a atualização de estatísticas, se isso for esquecido as consultas em tabelas On-Disk estaram provavelmente mais rápidas que as consultas em tabelas In-Memory.