In-Memory a.k.a OLTP “Hekaton” – Deep Dives [1]

Posted on julho 1, 2013

3


Armazenamento In-Memory

 

O armazenamento de tabelas e indices são lidados de forma diferente quando estamos utilizando essa nova tecnologia do XVelocity, tabelas que são otimizadas para estarem em memória (memory-optimized tables) não são armazenadas em páginas como no modelo baseado em armazenamento em disco (disk-based tables) a grande diferença é que registros de uma tabela pode não estar necessariamente armazenado perto de outro registros da mesma tabela e a única forma de garantir com que o registro pertença a uma tabela é a utilização de índices. Com isso todas as tabelas que forem colocadas no “Hekaton” devem  pelo menos um índice criado para a mesma. A nova estrutura de armazenamento dos registros segue da seguinte forma:

 

Row Header (Cabeçalho de Linhas)

image

(Figura 1 – Estrutura de armazenamento no “Hekaton” – Cabeçalho de linhas.)

 

O cabeçalho possui o Begin-Ts e o End-Ts cada um com 4-bytes de armazenamento no qual guardam o valor de timestamp ou seja a data em que a transação foi gravada sendo que o BeginTs é a data de início no qual o registro foi inserido enquanto o End-Ts é a data em que a transação foi deletada, se não houver valor no campo então um valor especial dado como ‘infinito’ é colocada para representar que o registro não foi deletado. O SmtId possui 4-bytes e representa cada declaração que é realizada sendo um unique, ele representa o valor unico de cada declaração realizada. E por final o IdxLinkCount que contêm 2-bytes e é o campo que faz a referência a quantidade de índices criados para essa linha ou seja esse campo nada mais é do que um ponteiro para o índice.

 

Payload (Área de Carga)

image

(Figura 2 – Estrutura de armazenamento no “Hekaton” – Área de Carga.)

Nessa área é aonde está armazenado de fato os registros e todos o campos da tabela, ou seja nessa área temos a chave da tabela com todas as suas colunas armazenadas, com isso se pensarmos bem essa área é como e fosse nosso covering index.

 

 Key Lookup Vs Hash Index

Key Lookup

Quando o Q.O realiza uma busca no índice secundário so que pela falta das informações dentro desse índice é necessário com que ele já para o nível primário para buscar o restante da informação isso que chamamos de Key Lookup. Essa operação é uma operação custosa para o banco de dados ou seja imagine que estamos realizando uma consulta no banco de dados e estamos procurando pelo nome porém queremos não somente o nome como retorno mais sim nome, idade e sexo. Há um índice criado em cima do campo nome o Q.O irá utilizá-lo porém na hora na qual ele tentar retornar todos os campos o mesmo não estará presente no nível folha com isso no final de ter andado na estrutura do índice secundário ele terá que ir buscar os outros campos sexo e idade no índice primário ou seja a tabela estar em memória não quer dizer que a mesma bela está otimizada em memória.

 

Hash-Key

Um hash index consiste em um ponteiro de arrays onde cada registro fica armazenado em bucket’s. Quando um registro é adicionado dentro de um bucket uma função hash é aplicada nesse registro e colocado dentro de um bucket, para maiores infiormações veja o post do ivan lima -  http://ivanglima.com/sql-server-xtp-hekaton-hash-indexes/

 

Sendo assim se criarmos um índice em cima do campo nome o hash key é muito mais performático para equalidades porque não é necessário que o mesmo desça até o nível folha para ser encontrado é necessário somente verificar qual valor hash que o nome representa e buscá-lo em memória, lembrando que os índices hash’s são criados somente em memória com isso não gastamos espaço em disco além de não duplicarmos o valor na tabela.

 

image   image

(Figura 3 – Key Lookup em cima do nome.)                       (Figura 4 – Hash Index em cima do nome.)

 

 Criação do Banco de Dados

 

A criação do banco de dados no “Hekaton” é simples diferenciando que é nececessário que você especifique um FILEGROUP especial contendo MEMORY_OPTIMIZED_DATA.

 

USE master

go

CREATE DATABASE InMemoryDB

ON PRIMARY

(

              NAME = ‘InMemoryDB’,

              FILENAME = ‘C:\BaseDados\mdf\InMemoryDB.mdf’,

              SIZE = 800MB

),

FILEGROUP Hekaton CONTAINS MEMORY_OPTIMIZED_DATA

(

              NAME = HK_Data1,

              FILENAME = ‘C:\BaseDados\mdf\HK_Data1’

),

(

              NAME = HK_Data2,

              FILENAME = ‘C:\BaseDados\mdf\HK_Data2’

)

LOG ON

(

              NAME = InMemoryDB_log,

              FILENAME = ‘C:\BaseDados\ldf\InMemoryDB_log.ldf’,

              SIZE = 500MB

)

O mecanismo de armazenamento do “Hekaton” é diferente, com isso é utilizado o filestream, que é totalmente vinculado para o filegroup criado. Há dois tipos de arquivos que são os Data Files e o Delta Files.

Data File – Nesse arquivo é somente guardado os registros que são inseridos ou seja os que são persistidos em disco independente da quantidade de tabelas dentro do filegroup a gravação desses registros são de forma sempre sequencial o que faz com que a velocidade de gravação seja muito mais efetiva. O que é importante notar é que dentro de uma página no “Hekaton” são armazenados diversas tabelas e no modelo normal do SQL Server são diferenciados por tabela.

Delta File – O arquivo Delta serve para trabalhar com as exclusões que são geradas, quando um registro é excluido do arquivo, ao invés de ir no arquivo de dados o “Hekaton" marca no arquivo qual linha foi retirada, com isso a velocidade da operação é muito mais eficiente.

De acordo com que as transações são executadas e colocadas no arquivo de log do SQL Server o “Hekaton” necessita lidar com as mesmas de forma eficiente, com isso os arquivos data e delta files são distribuidos por ranges e com isso para cada data file existe um delta files com os registros que foram excluídos, o que acontece é que quando um thread offline de checkpoint acontece no filegroup MEMORY_OPTIMIZED_DATA para por exemplo registros que foram deletados os mesmo são colocados no arquivo delta daquele range específico e quando inseridos da mesma forma.

 

 Operação Merge

 

Os registros excluídos que estão no arquivo delta precisam de uma operação MERGE para que o arquivo de Data não fique com registros que não existem mais e para que o arquivo DELTA não possua registros absoletos, com isso os dois arquivos são comparados fazendo com que a quantidade de arquivo de DATA e DELTA sejam menores além de aumentar a velocidade no processo de recovery do banco de dados na hora da carga dos arquivos para colocá-lo em memória sendo que esse recurso não faz parte do checkpoint, ele é um processo separado.

 

image 

(Figura 5 – Arquivos que seram feitos a operação de MERGE.)

Como esses ranges possuem uma grande quantidade de registros dentro dos arquivo de DELTA a operação de MERGE aconteçe com isso esse arquivos são comparados…

 

image

(Figura 6 – Os arquivo realizando a operação de MERGE.)

 

Quando os arquivos iniciam o processo de MERGE é importante lembrar que a operação é totalmente online e logo após isso os arquivos são unidos fazendo com que a quantidade de arquivos diminuam.

 

image

(Figura 7 – O novo arquivo de Data e Delta.)

 

Após a operação ser realizada os arquivos anteriores são excluídos e com isso um novo arquivo de Data e Delta são criados agora contendo os ranges dos arquivos anteriores.

 

 Considerações de Armazenamento

 

Um bom guia é sempre possuir 2 a 3x o espaço em disco do tamanho de cada tabela para o arquivo de Data que está in-memory, o que é importante é que não é necessário se preocupar em relação a escrita sequencial porque o “Hekaton” sempre irá lhe garantir isso. Todas as alterações feitas no “Hekaton” são totalmente integradas com o transactional log porém o mesmo é otimizado para trabalhar com esse recurso, se possível sempre utilize discos SSD’s para melhor performance.