E aí meu povo,
Você já ouviu falar do In-Memory OLTP? Pra que ele serve? Quais problemas ele pode causar? Bora aprender um pouco?
Vou começar uma pequena série de posts sobre o In-Memory OLTP! Nesse primeiro post vou explicar alguns conceitos básicos, no próximo mostro um problema real do dia a dia relacionado a utilização de memória e por último falo sobre alguns erros comuns.
Casos do Dia a Dia – In-Memory OLTP – Conceitos Básicos
Casos do Dia a Dia – In-Memory OLTP – Use com Moderação – Problema Utilização Memória
Casos do Dia a Dia – In-Memory OLTP – Mensagens de Erro
Vem comigo!!! #gogogo
In-Memory OLTP – Conceitos Básicos:
Você sabe o que é In-Memory OLTP? Pra mim era igual caviar, só ouvia falar…
Até que um certo dia, recebemos um chamado de um cliente que informou que estava com lentidão no banco de dados. Mas vou deixar pra contar esse caso no próximo post.
Nesse primeiro post da série, vou introduzir alguns conceitos básicos. Não vou entrar em muitos detalhes, mas no final do post eu inclui vários links e vídeos pra você poder se aprofundar ainda mais no assunto. Então vamos começar!
“Luiz, o que é esse tal de In-Memory OLTP? Pra que ele serve?”
O In-Memory (também conhecido como “memory optimized tables” ou “Hekaton”) foi adicionado no SQL Server 2014 somente para a versão Enterprise. A partir do SQL Server 2016 SP1, ele foi liberado para todas as versões (Standard, Web e Express). A cada nova versão do SQL Server eles melhoram ainda mais essa feature e corrigem algumas limitações.
Ele chegou com a ideia de melhorar a performance de ambiente críticos. Agora podemos priorizar algumas tabelas para ficar direto na memória e sem gerar locks. TOP!!!
Contudo, devido às limitações que veremos a seguir, acredito que ele não seja aplicável para todos os ambientes e deve ser utilizado com moderação! É, não existe almoço grátis né. =)
CUIDADO: Uma vez criado em sua base de produção, o FILEGROUP NÃO PODERÁ SER REMOVIDO! Portanto, utilize uma base de teste primeiro para ter certeza se vai criar na produção mesmo! Vou falar melhor sobre esse erro no terceiro post da série.
Cannot drop the last memory-optimized container ‘Teste_In_Memory’.
Msg 5042, Level 16, State 8, Line 153
The filegroup ‘Teste_In_Memory’ cannot be removed because it is not empty.
In-Memory OLTP – Limitações:
“Luiz, fiquei sabendo que o In-Memory é TOP! Já vou começar a utilizar ele na minha produção!”
CUIDADO! Ele possui uma série de limitações e isso pode ser bem PERIGOSO! Por isso ele deve ser bem entendido antes de ser utilizado na produção! O link abaixo é excelente para introduzir esses conceitos básicos.
Algumas das limitações abaixo já podem ter sido contornadas nas novas versões do SQL Server. O que quero reforçar aqui é que o In-Memory possui várias limitações e sugiro que você valide se alguma delas pode impactar no seu ambiente.
In-Memory OLTP – Cenários Úteis:
“Beleza Luiz, mas em que cenários ele pode ser útil?”
O Murilo Miranda resume bem alguns cenários onde o In-Memory pode ser utilizado:
https://www.sqlshack.com/in-memory-oltp-the-faster-is-now-simpler/
In-Memory OLTP – Performance – Isolation Level x Locks:
“Hum, agora me explica por que ele não gera Locks!”
Uma das vantagens de utilizar o In-Memory é que ele evita Locks, pois utiliza o conceito de “Row Versions” semelhante ao Read Committed Snapshot Isolation (RCSI). Já as tabelas normais utilizam por padrão o Read Committed e por isso geram Locks. Mais detalhes sobre Isolation Level no link abaixo:
In-Memory OLTP – Performance – Index – Hash x Nonclustered:
Os índices nas “memory optimized tables” são diferentes das tabelas tradicionais. Por exemplo, no In-Memory a quantidade de índices por tabela é mais limitada.
As operações nesses índices são mais rápidas, pois eles já estão na memória e não precisam acessar o disco. Quando acontece um restart na instância, o índice será recriado na memória.
OBS: Mais detalhes sobre “Indexes on Memory-Optimized Tables” no link a seguir:
De forma resumida, existem dois tipos de índices (não vou citar aqui o Columnstore Index):
Hash Indexes:
Consiste em uma coleção de buckets organizados em um array de ponteiros. Quando um novo registro é inserido, uma “função hash” é aplicada sobre ele para definir em qual bucket ele será inserido.
Um ponto importante nesse caso é a escolha do valor adequado para o BUCKET_COUNT, ele não pode ser nem muito pequeno nem muto grande, pois pode afetar diretamente na performance. Portanto, pense bem no momento que for criar a tabela.
Ele é mais performático quando a coluna tiver poucos valores repetidos e for utilizado com filtros de igualdade. Segue um exemplo:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
USE Teste GO IF (OBJECT_ID('InMemoryExample') IS NOT NULL) DROP TABLE InMemoryExample CREATE TABLE dbo.InMemoryExample ( OrderID INTEGER NOT NULL IDENTITY , Name VARCHAR(4000) NOT NULL, PRIMARY KEY NONCLUSTERED HASH (Name) WITH (BUCKET_COUNT = 10000) ) WITH (MEMORY_OPTIMIZED = ON, DURABILITY = SCHEMA_AND_DATA); SELECT * FROM InMemoryExample WHERE Name = 'Luiz Vitor França Lima' |
O exemplo abaixo mostra a representação de um “Hash Index” na coluna “City”. A função hash recebe o valor “New York” e gera um hash que identifica o seu respectivo bucket. Quando um segundo registro for inserido com o mesmo valor, será gerado uma cadeia e assim por diante.
Nonclustered Indexes:
Utiliza uma estrutura chamada “Bw-Tree”, que é uma variação da já conhecida B-Tree. Esse tipo de índice é mais performático quando é utilizado para retornar um conjunto de linhas baseado em um intervalo. Por exemplo, quando utiliza os filtros com operadores de intervalos: >, <, >=, <= ou BETWEEN.
1 2 3 4 5 |
USE Teste SELECT * FROM InMemoryExample WHERE [OrderID] < 1000 |
Na figura abaixo, a estrutura da Bw-Tree é quase a mesma da B-Tree. Cada página tem um conjunto de valores ordenados que apontam para o próximo nível. No nível intermediário, os ponteiros indicam páginas, enquanto no nível folha (leaf level) eles referenciam os registros de dados.
Se o valor para o “Index Key” for o mesmo para vários registros, uma cadeia será criada, assim como acontece no Hash Index.
Utilizei as imagens do artigo abaixo do Murilo Miranda:
In-Memory OLTP – Create Table and Durability:
“Luiz, mas se os dados estão na memória, quando o SQL Server for reiniciado eles não serão perdidos?”
Depende. Aqui precisamos entender o conceito de DURABILITY que possui duas opções:
SCHEMA_ONLY:
Aqui os dados não são persistidos no disco, ou seja, quando o SQL Server for reiniciado eles SERÃO PERDIDOS!
Contudo, ele mantém no disco apenas os metadados ou estrutura da tabela e isso não será perdido com o restart.
Isso pode ser útil para tabelas temporárias.
SCHEMA_AND_DATA:
Essa opção irá persistir no disco os dados e a estrutura da tabela.
Deve ser utilizada nas tabelas que não podem perder dados com um restart.
Na criação de uma tabela In-Memory, agora também precisaremos utilizar o MEMORY_OPTIMIZED = ON.
Vamos fazer um teste para entender melhor. Vou criar uma tabela utilizando o SCHEMA_ONLY e outra utilizando o SCHEMA_AND_DATA e depois vou inserir alguns registros.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 |
-- TESTE - TABELA SCHEMA_ONLY x SCHEMA_AND_DATA GO USE Teste GO IF (OBJECT_ID('InMemoryExampleSchemaOnly') IS NOT NULL) DROP TABLE InMemoryExampleSchemaOnly CREATE TABLE dbo.InMemoryExampleSchemaOnly ( [ID] INTEGER NOT NULL IDENTITY PRIMARY KEY NONCLUSTERED, [Message] VARCHAR(4000) NOT NULL ) WITH (MEMORY_OPTIMIZED = ON, DURABILITY = SCHEMA_ONLY); IF (OBJECT_ID('InMemoryExampleSchemaAndData') IS NOT NULL) DROP TABLE InMemoryExampleSchemaAndData CREATE TABLE dbo.InMemoryExampleSchemaAndData ( [ID] INTEGER NOT NULL IDENTITY PRIMARY KEY NONCLUSTERED, [Message] VARCHAR(4000) NOT NULL ) WITH (MEMORY_OPTIMIZED = ON, DURABILITY = SCHEMA_AND_DATA); INSERT INTO InMemoryExampleSchemaOnly VALUES('Estou aqui!!'), ('Mas após o Restart'), ('Não vou estar mais =(') INSERT INTO InMemoryExampleSchemaAndData VALUES('Eu vou ficar aqui'), ('Mesmo depois do Restart'), ('Uhuuull!!!') SELECT * FROM InMemoryExampleSchemaOnly SELECT * FROM InMemoryExampleSchemaAndData |
Agora, vou fazer um Restart no SQL Server e conferir o que vai acontecer com os dados. Será que eles vão sumir???
1 2 3 4 5 6 7 |
-- FAZER UM RESTART NO SQL SERVER E CONFERIR NOVAMENTE AS TABELAS USE Teste SELECT * FROM InMemoryExampleSchemaOnly SELECT * FROM InMemoryExampleSchemaAndData |
“Que loucura Luiz, os dados somem mesmo!!!”
Pois é! Tome bastante cuidado ao escolher o DURABILITY para as suas tabelas!
Uma outra observação importante é que ao criar uma tabela In-Memory nós precisamos especificar um índice. Repare que temos erros diferentes para o SCHEMA_ONLY e o SCHEMA_AND_DATA:
DURABILITY = SCHEMA_ONLY
1 2 3 4 5 6 7 8 9 10 11 12 |
USE Teste IF (OBJECT_ID('InMemorySchemaWithoutIndex') IS NOT NULL) DROP TABLE InMemorySchemaWithoutIndex CREATE TABLE dbo.InMemorySchemaWithoutIndex ( [ID] INTEGER NOT NULL ,-- IDENTITY PRIMARY KEY NONCLUSTERED, [Message] VARCHAR(4000) NOT NULL ) WITH (MEMORY_OPTIMIZED = ON, DURABILITY = SCHEMA_ONLY); |
Msg 41327, Level 16, State 7, Line 6
The memory optimized table ‘InMemorySchemaWithoutIndex’ must have at least one index or a primary key.
Msg 1750, Level 16, State 0, Line 6
Could not create constraint or index. See previous errors.
DURABILITY = SCHEMA_AND_DATA
1 2 3 4 5 6 7 8 9 10 |
IF (OBJECT_ID('InMemoryDataWithoutIndex') IS NOT NULL) DROP TABLE InMemoryDataWithoutIndex CREATE TABLE dbo.InMemoryDataWithoutIndex ( [ID] INTEGER NOT NULL ,-- IDENTITY PRIMARY KEY NONCLUSTERED, [Message] VARCHAR(4000) NOT NULL ) WITH (MEMORY_OPTIMIZED = ON, DURABILITY = SCHEMA_AND_DATA); |
Msg 41321, Level 16, State 7, Line 23
The memory optimized table ‘InMemoryDataWithoutIndex’ with DURABILITY=SCHEMA_AND_DATA must have a primary key.
Msg 1750, Level 16, State 0, Line 23
Could not create constraint or index. See previous errors.
In-Memory OLTP – Limitação de Recursos – Resource Governor x Resource Pool:
O Resource Governor foi introduzido no SQL Server 2008. Com ele nós podemos, por exemplo, limitar os recursos (CPU, memória, IOPS) que são utilizados por uma determinada database.
Infelizmente, essa feature está disponível somente nas versões SQL Server Enterprise / Developer!
“Interessante Luiz, e como isso pode nos ajudar?”
Uma boa prática no In-Memory é você limitar os recursos para proteger a memória e evitar um consumo inesperado das “memory optimized tables”, pois isso pode gerar sérios problemas de performance. No próximo post vou mostrar um caso real com esse problema.
O Resource Pool representa os recursos físicos do servidor. No exemplo abaixo, nós criamos um pool para limitar a quantidade de recursos que ele poderá utilizar. Depois, basta associar uma database a esse pool que ela irá respeitar essas limitações. Com isso, nós podemos limitar as databases que utilizam o In-Memory para que elas não roubem” toda a memória disponível no servidor.
1 2 3 4 5 6 7 8 9 10 11 12 |
CREATE RESOURCE POOL [PoolA] WITH ( MIN_CPU_PERCENT=0, MAX_CPU_PERCENT=20, CAP_CPU_PERCENT=20, MIN_MEMORY_PERCENT=0, MAX_MEMORY_PERCENT=30, AFFINITY SCHEDULER = AUTO, MIN_IOPS_PER_VOLUME=0, MAX_IOPS_PER_VOLUME=300 ) GO |
Veja as referências abaixo para ter mais detalhes e aprender a configurar o Resource Governor:
https://www.outsystems.com/blog/posts/manage-database-resources/
In-Memory OLTP – Armazenamento – Checkpoint File x Data File x Delta File:
A forma de armazenamento do In-Memory é diferente das tabelas normais. Ele também utiliza o disco para manter os seus dados seguros, mas com um mecanismo de controle diferente.
“Como assim Luiz? Mas os dados não ficam na memória?”
Sim, mas tenha calma. A memória é volátil e quando o SQL Server for reiniciado esses dados serão perdidos. Para contornar esse problema, o SQL Server utiliza um arquivo não volátil denominado Checkpoint File que é salvo em disco.
Esse arquivo é armazenado em um container definido no Memory-Optimized Filegroup de cada database e cada uma delas pode ter vários containers.
Segue abaixo um exemplo de como os Checkpoint Files são armazenados no disco:
O “Checkpoint File” funciona com pares de arquivos. São eles:
- Data File: Possui os registros inseridos.
- Delta File: Possui os registros que foram excluídos do seu Data File correspondente. Por isso eles funcionam em pares.
OBS: O UPDATE é tratado como um INSERT e DELETE.
Por fim, existem vários Checkpoint Files, cada um responsável pelo armazenamento dos dados em um determinado período do tempo. Posteriormente, o Garbage Collector será responsável por excluir os arquivos antigos. Nesse ponto, precisamos monitorar com atenção o espaço em disco, pois esses arquivos podem crescer demais com o passar do tempo. Ou seja, tome bastante cuidado se você não tiver muito espaço livre em disco.
Utilizei a imagem abaixo de uma apresentação do Felipe de Assis – “SQL In-Memory aka Hekaton 101” em um SQL Saturday. Ela resume bem a estrutura dos arquivos.
In-Memory OLTP – Liberação de Memória – Garbage Collector (GC):
O Garbage Collector (GC) é responsável por fazer o gerenciamento da limpeza da memória utilizada pelo In-Memory. Coloquei um print do link abaixo com algumas informações muito interessantes.
No próximo post vou mostrar um caso real com um problema relacionado ao Garbage Collector, onde ele não estava liberando a memória não utilizada.
Segue mais alguns links como referência:
https://luanmorenodba.wordpress.com/2013/08/16/in-memory-a-k-a-oltp-hekaton-deep-dives-4/
Conclusão:
Como podemos ver, o In-Memory é uma feature muito interessante e podemos ter ganhos de performance com ele. Contudo, devemos entender muito bem como ele funciona, suas limitações e os problemas que pode causar. Compreendendo esses pontos, podemos tomar uma decisão com mais segurança para implantar ou não nos nossos ambientes.
Minhas considerações finais são:
- Se você tem um servidor com pouca memória, CUIDADO! O In-Memory pode ser bem perigoso e consumir toda a memória disponível! Veja o próximo post da série; xD
- Se você NÃO utiliza a versão do SQL Server Enterprise, CUIDADO! Você não irá conseguir utilizar o Resource Governor para limitar os recursos e isso pode ser bem perigoso!
- Se o seu servidor estiver com pouco espaço livre em disco, CUIDADO! Você pode ter problemas com o crescimento dos Checkpoint Files.
- Na prática como Consultor SQL Server, ainda não encontrei essa feature em produção em muitos clientes. Vamos ver se isso muda com o passar do tempo; =)
- Uma vez que o In-Memory for implantado no seu ambiente, tenha uma atenção maior na utilização de memória e no espaço em disco do seu servidor;
- Não implante nada nos seus ambientes sem entender bem como funciona e os problemas que podem ser gerados!
- Se for possível, faça um teste de stress e veja como o ambiente vai se comportar com uma carga maior de processamento, pois um dia o seu sistema irá crescer.
Espero que você tenha aprendido algo e não perca o próximo post da série! =)
Referências:
Separei alguns blogs e vídeos para que vocês possam se aprofundar ainda mais no assunto. Eles me ajudaram demais!!! #ficaadica
- TOP 4 – Blogs – In-Memory:
Monica Rathbun – Beginner Guide to In-Memory Optimized Tables in SQL Server
Luan Moreno – Série de Posts sobre o In-Memory:
https://luanmorenodba.wordpress.com/tag/in-memory/page/1/
https://luanmorenodba.wordpress.com/2013/06/05/in-memory-oltp-hekaton-parte1/
https://luanmorenodba.wordpress.com/2013/07/01/in-memory-a-k-a-oltp-hekaton-deep-dives-1/
https://luanmorenodba.wordpress.com/2013/07/08/in-memory-a-k-a-oltp-hekaton-deep-dives-2/
https://luanmorenodba.wordpress.com/2013/07/29/in-memory-a-k-a-oltp-hekaton-deep-dives-3/
https://luanmorenodba.wordpress.com/2013/08/16/in-memory-a-k-a-oltp-hekaton-deep-dives-4/
Murilo Miranda – Série de Posts sobre o In-Memory:
https://www.sqlshack.com/in-memory-oltp-the-faster-is-now-simpler/
David Barbarin – Memory management, OOM issues with SQL Server 2014 In-memory OLTP
https://blog.dbi-services.com/memory-management-oom-issues-with-in-memory-oltp/
- TOP 3 – Vídeos – In-Memory:
Luan Moreno – Webcast Virtual PASS PT – Cenários de Utilização In Memory OLTP a k a ‘Hekaton
https://www.youtube.com/watch?v=YzLc69dyIjw
Bob Ward – SQL SERVER IN-MEMORY OLTP: WHAT EVERY SQL PROFESSIONAL SHOULD KNOW
https://www.youtube.com/watch?v=uXZF1gug6pU
Dmitri Korotkevitch – SQL Maniacs – In-Memory OLTP: Architecture, Implementation and SQL Server 2016 enhancements
https://www.youtube.com/watch?v=VvjBs0PowAE
Segue mais alguns links de referência:
https://docs.microsoft.com/pt-br/archive/blogs/fcatae/historia-do-hekaton-parte-1
https://docs.microsoft.com/pt-br/archive/blogs/fcatae/historia-do-hekaton-parte-2
https://docs.microsoft.com/pt-br/archive/blogs/fcatae/historia-do-hekaton-parte-3
https://www.brentozar.com/archive/2011/09/sysadmins-guide-microsoft-sql-server-memory/
https://blog.sqlauthority.com/2010/12/13/sql-server-what-is-page-life-expectancy-ple-counter/
- Mais Vídeos:
Artemakis Artemiou – Getting Started with SQL Server In-Memory OLTP
https://www.youtube.com/watch?v=SExtYPovtOk
Bob Ward – Inside SQL Server In-Memory OLTP with Bob Ward
https://www.youtube.com/watch?v=P9DnjQqE0Gc
Espero que tenha gostado e que isso também possa ser útil no seu dia a dia. Até o próximo post!
Me siga no LinkedIn e YouTube para ficar por dentro das novidades.
Abraço,
Luiz Vitor França Lima
Consultor SQL Server
Muito bom. Creio que depois de publicar os próximos teremos uma excelente fonte sobre o assunto de forma mais completa. Começou muito bem, mantendo o alto padrão dos teus posts. . Eu tenho uma certa ansiedade de usar por causa da proposta de melhor desempenho, mas ainda não tive uma situação que fosse ideal para isso. Talvez com mais conhecimento eu perceba onde aplicar de forma eficiente. Abração
Obrigado pelo feedback Alexandre! Pois eh, o In-Memory não é algo tão simples e requer alguns cuidados especiais. No próximo post, vou mostrar um caso de uso que pode ser perigoso e que acabou gerando problemas em um cliente.
Abraço,
Luiz Vitor
Pingback: Casos do Dia a Dia – In-Memory OLTP – Use com Moderação – Problema Utilização Memória – Luiz Lima
Pingback: Casos do Dia a Dia – In-Memory OLTP – Mensagens de Erro – Luiz Lima