In-Memory OLTP - Melhorias no Transaction Logging

In-Memory OLTP - Melhorias no Transaction Logging

O Transaction Log é responsável por gravar todas as modificações realizadas por uma transação. Ele é essencial para o caso de uma falha (ex. falta de energia) o arquivo de Log é fundamental no processo de Recovery e trazer o banco de dados a um estado consistente.

Podemos ainda dizer que a capacidade de gravação de um banco de dados é limitada pela capacidade de gravação dos dados no Transaction Log.

O SQL Server 2014 introduziu uma série de melhorias com relação ao transaction log, para que fosse possivel manter a consistencia dos dados das tabelas In-Memory. Isso se deve ao fato de que as tabelas na memória precisam persisitir no Log da mesma maneira que é feito hoje nas tabelas no disco.

A feature In-Memory do SQL Server 2014 foi criada principalmente para resolver problemas de concorrência física quando vários usuários ao mesmo mesmo tempo fazem alterações em uma mesma Página/Estrutura Física em memória, o que chamamos de concorrência por Latch.

As operações nas tabelas In-Memory são operações muito rápidas e para que a performance do In-Mermory não fosse prejudicada foram feitas uma série de melhorias com relação ao transacion Log, essas melhorias são as seguintes:

  • As operações de Insert e delete requerem menos espaço de gravações do que as tabelas em disco.
  • In-Mermoy OLTP tenta agupar os registros de Log em um grande registro de Log com até 24KB, e com isso reduzir a quantidade de escritas.
  • Agora o  In-Memory utiliza um modelo de concorrência otimista e as operações são gravadas apenas no momento do Commit, ao contrário das tabelas de disco que todos os passos erram gravados para possiblitar o Rollback das operações. Ou seja ele efetua todas alterações passo a passo e só grava no log no momento do Commit e isso reduz o número de vezes que uma transação precisa escrever no Log Buffer.
  • As alterações nos índices In-Memory não são Logadas, com isso há um número muito menor de registros gerados no Transaction Log, caso ocorra restart da instância os índices das tabelas In-Memory são criados no processo de Recovery.

O ponto que gostaria de chamar atenção nesse artigo, é que além das melhorias citadas acima que ocorreram no produto, é recomendado que sejam utilizados discos SSD no volume onde é armazenado o arquivo de Log, caso contrário o ganho de performance com as tabelas In-Memory podem ser impossilitados ou suprimidos, porque mesmo as operações In-Memory (muito rápidas e sem Latch) precisam persistir no disco e quanto mais rapido a gravação no log ocorrer, melhor.

Veja agora uma DEMO que ilustra uma grande redução de Log nas transações das tabelas In-Memory:

O trecho abaixo irá criar um banco de dados com o nome de Demolog

USE master

GO

IF EXISTS (SELECT * FROM sys.databases WHERE name='DemoLog')

DROP DATABASE DemoLog;

GO

CREATE DATABASE DemoLog ON 

 PRIMARY (NAME= [DemoLog_data], FILENAME ='C:\DataHK\DemoLog_data.mdf'),

 FILEGROUP [DemoLog_FG] CONTAINS MEMORY_OPTIMIZED_DATA

 (NAME= [DemoLog_InMemory1],  FILENAME = 'C:\DataHK\StorageDemo_DemoLog_InMemory1')

 LOG ON (name = [DemoLog_log], Filename='C:\DataHK\StorageDemoLog_InMemory_log.ldf', size=100MB);

GO

--Agora vamos criar duas tabelas uma em Memoria com o nome de InMemoryLog e outra no disco com nome de DiscoLog.

USE DemoLog

GO

IF EXISTS (SELECT * FROM sys.objects WHERE name='InMemoryLog')

DROP TABLE [dbo].[InMemoryLog]

GO

-- Cria uma tabela In-Memory

CREATE TABLE [dbo].[InMemoryLog]

( [Campo1] int NOT NULL,

  [Campo2] char(100) NOT NULL, 

  CONSTRAINT [pk_InMemoryLog_campo1] PRIMARY KEY NONCLUSTERED HASH ([campo1])

  WITH(BUCKET_COUNT = 1000000)

) WITH (MEMORY_OPTIMIZED =ON,

 DURABILITY = SCHEMA_AND_DATA);

GO

IF EXISTS (SELECT * FROM sys.objects WHERE name='DiscoLog')

                   DROP TABLE [dbo].[DiscoLog]

GO

--Vamos criar uma tabela similar no disco.

 CREATE TABLE [dbo].[DiscoLog]

( [Campo1] int NOT NULL,

  [Campo2] char(100) NOT NULL)

GO

CREATE UNIQUE NONCLUSTERED INDEX ix_discoLog_campo1 on DiscoLog(Campo1);

GO

--Agora vamos inserir alguns registros na tabela e examinar o log com a função fn_dblog().

BEGIN TRAN

DECLARE @i int = 0

WHILE (@i < 100)

BEGIN

     INSERT INTO DiscoLog VALUES (@i, replicate ('1', 100))

      SET @i = @I + 1

END

COMMIT

--Veja que foram inseridos 200 registros no log.

SELECT *
FROM sys.fn_dblog(NULL, NULL)

WHERE PartitionId IN

     (SELECT partition_id FROM sys.partitions

      WHERE object_id=object_id('DiscoLog'))

ORDER BY [Current LSN] ASC;

GO

--Agora vamos rodar um script similar para inserir os dados nas tabelas In-Memory

 BEGIN TRAN

DECLARE @i int = 0

WHILE (@i < 100)

BEGIN

      INSERT INTO InMemoryLog VALUES (@i, replicate ('1', 100))

      SET @i = @i + 1

END

COMMIT

-- Olhe o Log

SELECT *
FROM sys.fn_dblog(NULL, NULL) order by [Current LSN] DESC;

GO

 

 Veja na imagem acima que há apenas um registro de LOG para todos os 100 Inserts com o tipo de LOP_HK, LOP indica que é uma operação lógica e HK é a inicial do do nome Hekaton que era o nome do projeto do In-Memory.

Agora utilize a query abaixo para visualizar o registros agrupados In-Memory (Veja o LSN da operação).

SELECT [current lsn], [transaction id], operation,

       operation_desc, tx_end_timestamp, total_size,

       object_name(table_id) AS TableName

FROM sys.fn_dblog_xtp(null, null)

WHERE [Current LSN] = '00000020:0000015f:0004';

Com isso, termino minha explicação sobre Log no In-Memory, espero que tenham gostado, até a próxima!

Alberto Lima - SQL Server PFE